【问题标题】:C program runs in Cygwin but not Linux (Malloc)C 程序在 Cygwin 中运行,但不在 Linux (Malloc) 中运行
【发布时间】:2011-02-15 13:14:14
【问题描述】:

我有一个堆分配错误,我无法在我的代码中发现该错误,该错误在 Linux 上的 vanguard/gdb 上被拾取,但在 Windows cygwin 环境中完美运行。我知道 Linux 的堆分配可能比 Windows 更严格,但我真的很想得到一个发现问题/可能修复的回应。我也知道我不应该在 C 中对 malloc 进行类型转换,但这是一种习惯的力量,不会改变我的问题的发生。我的程序实际上在 Linux 和 Windows 上都没有错误地编译,但是当我在 Linux 中运行它时,我得到了一个看起来很吓人的结果:

malloc.c:3074: sSYSMALLOc: 断言 `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof (size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' 失败。 中止

我的代码中的附加 sn-p 被指出为错误以供审查:

/* Main */

int main(int argc, char * argv[]) {

    FILE *pFile;  
    unsigned char *buffer;  
    long int lSize;  

    pFile = fopen ( argv[1] , "r" );
    if (pFile==NULL) {fputs ("File error on arg[1]",stderr); return 1;}

    fseek (pFile , 0 , SEEK_END);
    lSize = ftell (pFile);
    rewind (pFile);

    buffer = (char*) malloc(sizeof(char) * lSize+1);
    if (buffer == NULL) {fputs ("Memory error",stderr); return 2;}

    bitpair * ppairs = (bitpair *) malloc(sizeof(bitpair) * (lSize+1));

    //line 51 below
    calcpair(ppairs, (lSize+1));

    /* irrelevant stuff */

    fclose(pFile);
    free(buffer);
    free(ppairs);  
}

typedef struct {  
long unsigned int a;  //not actual variable names...  Yes I need them to be long unsigned  
long unsigned int b;  
long unsigned int c;  
long unsigned int d;  
long unsigned int e;  
} bitpair;  

void calcpair(bitpair * ppairs, long int bits);

void calcPairs(bitpair * ppairs, long int bits) {

    long int i, top, bot, var_1, var_2;
    int count = 0;

    for(i = 0; i < bits; i++) {

        top = 0;

        ppairs[top].e = 1;

        do {
            bot = count;
            count++;
        } while(ppairs[bot].e != 0);

        ppairs[bot].e = 1;

        var_1 = bot;
        var_2 = top;

        bitpair * bp = &ppairs[var_2];
        bp->a = var_2;
        bp->b = var_1;
        bp->c = i;

        bp = &ppairs[var_1];
        bp->a = var_2;
        bp->b = var_1;
        bp->c = i;

    }

    return;
}

gdb 报告:free():无效指针:0x0000000000603290 *

由于“VALGRIND INTERNAL ERROR”信号 11 (SIGSEGV),valgrind 在退出前 5 次报告以下消息:
大小为 8 的无效读取
==2727== 在 0x401043: calcPairs (在 /home/user/Documents/5-3/ubuntu test/main)
==2727== by 0x400C9A: main (main.c:51)
==2727== 地址 0x5a607a0 没有被堆栈、malloc 或(最近)释放

【问题讨论】:

  • 我认为你遗漏了有趣的部分.. calcpair() 中发生了什么?
  • 感谢 cmets,我已更新 OP 以包含 calcpair() 的 sn-p。 'buffer' 用于对第二个文件执行迭代 fread,一次 1 个字节:fread (buffer,1,1,pFile);
  • 对不起,迭代 fread 在 OP (pFile) 中打开的同一个文件上。
  • 这是你完整的calcPairs 函数还是只是一个sn-p?如果这就是全部,那么您有几个问题,其中最重要的是do {...} while 循环运行超过数组末尾的能力。
  • 如果您需要诊断帮助,请将您的全部资源放在网站上并链接到它。如果您没有自己的网站,pastebin.com 是一个好地方(但不是存档)。

标签: c gdb malloc valgrind


【解决方案1】:

看起来像数组溢出

没有什么能阻止这个循环超出 ppair 数组的末尾:

    do { 
        bot = count; 
        count++; 
    } while(ppairs[bot].e != 0); 

特别是因为这一行会覆盖你的终止零:

ppairs[bot].e = 1;

试试这个:

    do { 
        bot = count; 
        count++; 
    } while((bot < bits) && (ppairs[bot].e != 0)); 

你的, 汤姆

【讨论】:

    【解决方案2】:

    您似乎希望 malloc 返回预置零内存。

        do {
            bot = count;
            count++;
        } while(ppairs[bot].e != 0);
    

    无需找到归零的 ppairs[bot].e 即可轻松结束您的 ppairs[bot].e

    您想使用 calloc 而不是 malloc,这会在返回之前清除内存。

    bitpair * ppairs = (bitpair *) calloc(sizeof(bitpair) * (lSize+1));
    

    【讨论】:

    • 这有帮助,尽管您没有正确调用 calloc(需要 2 个参数): void * calloc ( size_t num, size_t size );当我使用 lSize+1 作为 num 的 calloc 并将上面的参数作为大小时,我可以针对小目标文件运行,但较大的目标文件 (40KB) 会从 if(ppairs==NULL) 生成内存错误。
    • 可能比使用calloc 更容易的是保留当前的malloc 调用并在分配后使用memset 将它们清零。
    • 我没有使用 memset 的经验,但在做:memset (ppairs, 0, lSize+1);与 ppairs 上的 malloc 一起编译,但仍然给出相同的堆错误
    • memset (ppairs, 0, sizeof(bitpair) * (lSize+1));
    • @aspo- 仍然在运行时给出 malloc 问题
    【解决方案3】:

    您对malloc 的第二次调用永远不会检查其返回值。修改它,使它看起来更像第一个,如:

    bitpair * ppairs = (bitpair *) malloc(sizeof(bitpair) * (lSize+1));
    if (ppairs == NULL) {fputs ("Memory error",stderr); free(buffer); return 3;}
    

    另外,请记住 malloc 需要 size_t(其定义取决于实现)作为参数。确保当您将(sizeof(bitpair) * (lSize+1)) 传递给malloc 时,您没有溢出size_t(如果size_t 被定义为unsigned int,您可能会遇到问题,因为lSizelong)。

    【讨论】:

    • 谢谢,我确实忘记了。不幸的是,malloc 问题仍然存在
    • 将函数中的 lSize 和相关变量更改为常规 int 会导致相同的运行时错误
    • 随机想法(可能会或可能不会改变任何东西):不要在调用malloc 的同一行中声明ppairs,而是在函数顶部声明它。另外,尝试将bitpair 的定义移到main 函数上方。
    【解决方案4】:

    在一个疯狂的猜测 ftell 返回 -1 并且 malloc 不喜欢被要求分配零字节。 malloc(0) 的行为取决于 C 中的实现。

    【讨论】:

    • 我可以通过测试确认 lSize 的大小是正确的,在这种情况下为 27(有时要大得多,因此需要很长时间)。
    • 它依赖于实现,但它必须返回一个指针值,您可以安全地传递给free()(包括NULL)。不允许中止。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-18
    • 2012-12-28
    • 1970-01-01
    相关资源
    最近更新 更多