Valgrind抱怨打电话给fgets

时间:2015-04-07 21:19:18

标签: c memory valgrind

我有这段代码:

int main(int argc, char const *argv[])
{
    FILE *fp = NULL;
    char *buffer = malloc(sizeof(char) * 150);
    char roomElements[150];
    char *roomSize = NULL;
    int i = 1;
    int *size = NULL; // does this need to be malloced?
    char input = '\0';

    check(argc == 2, "Please enter two arguments");

    fp = openFile((char*)argv[1], "r");

    initscr(); // ncurses
    noecho();


    /*Draws rooms and items*/
    while (fgets(buffer, 150, fp)) { // line 25
        removeNewLine(buffer);
        strcpy(roomElements, strchr(buffer, ' '));
        roomSize = strtok(buffer, " "); // get the room size
        size     = getRoomSize(roomSize, i); // convert room size to int pointer
        drawRoom(size, i); // draw the room
        tokenizeRoom(roomElements, i); // draw the elements
        i++;
        free(size);
    }

    /*This is the user input loop*/
    do {
        input = getch();
        getInput(input);
    } while (input != 'q');

    free(buffer);
    fclose(fp);
    endwin();

    return 0;
error:
    return -1;
}

Valgrind输出:

==74014== Memcheck, a memory error detector
==74014== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==74014== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info
==74014== Command: ./bin/rogue assets/room.txt
==74014== 
==74014== Invalid read of size 32
==74014==    at 0x10043EC1D: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==74014==    by 0x10023080A: fgets (in /usr/lib/system/libsystem_c.dylib) 
==74014==    by 0x100000E10: main (main.c:25)
==74014==  Address 0x100918a40 is 32 bytes before a block of size 4,096 in arena "client"                                                       
==74014== Conditional jump or move depends on uninitialised value(s)
==74014==    at 0x10043EC7A: _platform_memchr$VARIANT$Haswell (in /usr/lib/system/libsystem_platform.dylib)
==74014==    by 0x10023080A: fgets (in /usr/lib/system/libsystem_c.dylib)
==74014==    by 0x100000E10: main (main.c:25)
==74014==  Uninitialised value was created by a heap allocation
==74014==    at 0x100008601: malloc (vg_replace_malloc.c:303)
==74014==    by 0x100233836: __smakebuf (in /usr/lib/system/libsystem_c.dylib)
==74014==    by 0x100236E99: __srefill0 (in /usr/lib/system/libsystem_c.dylib)
==74014==    by 0x100236F94: __srefill (in /usr/lib/system/libsystem_c.dylib) 
==74014==    by 0x1002307DA: fgets (in /usr/lib/system/libsystem_c.dylib)

我可能做错了什么?一切都已初始化,我不知所措。关于这个主题没有其他答案可以帮助我。我不确定为什么它抱怨fgets要么。

第二次编辑,我将展示更多我的代码。 这是openFile()

FILE *openFile(char *file, char *mode) {
    FILE *fp = NULL;

    fp = fopen(file, mode);

    check(fp, "Could not open %s", file);

    return fp;
}

以下是getRoomSize

int *getRoomSize(char *size, int roomNum) { // rows x columns
    int row, col;
    char strRow[5], strCol[5];
    int *roomSize = malloc(sizeof(int) * 2);

    check(roomNum < 7 && roomNum > 0, "Invalid room to be drawn");

    /*Convert string to int*/
    strcpy(strRow, strtok(size, "X"));
    strcpy(strCol, strtok(NULL, "X"));
    row = atoi(strRow);
    col = atoi(strCol);

    roomSize[0] = row;
    roomSize[1] = col;

    return roomSize;
}

编辑3:这是我的MCVE。它会重现条件跳转和未初始化的值错误:

int main(int argc, char const *argv[])
{
    char *buffer= malloc(sizeof(char) * 150);
    char roomElements[300] = {0};
    int i = 1;
    FILE *fp = fopen(argv[1], "r");

    if (!fp) {
        printf("no\n");
        exit(0);
    }

    while (fgets(buffer, 150, fp)) {
        strcpy(roomElements, strchr(buffer, ' '));
        i++;
    }

    free(buffer);
    return 0;
}

该文件是.txt文件,其中包含此行6次:15X20 dn2 de10 dw11 g4,2 m10,17 M12,7 M4,9 p11,14 w10,10

1 个答案:

答案 0 :(得分:1)

我认为这可能是一种误报。

fgets在内部使用memchr来检查是否有新行。您的平台memchr是一个高度优化的汇编例程(名称表示它专门针对Haswell架构进行了优化),它一次读取32个字节以定位目标字符(可能使用一些SSE指令来执行此操作)。在缓冲区结束时,memchr在150字节分配结束时运行,并且valgrind会抱怨。

这是完全安全的;由于页面分配大小(至少)为4096字节,因此memchr如果坚持对齐的32字节边界,则不可能触及坏内存。如果它在未初始化的内存中找到目标字符,它可能会检测到找到的字符超过了它应该搜索的字符串的结尾,并在那种情况下返回正确的结果。

我会忽略这个错误。 Valgrind偶尔会产生误报;考虑获取或制作特定于平台的抑制文件,以自动忽略这些类型的错误警报。