【问题标题】:valgrind report memory loss using getline functionvalgrind 使用 getline 函数报告内存丢失
【发布时间】:2019-12-13 21:27:28
【问题描述】:

我正在用 C 语言编写一个 grep 程序。我在 while 循环中使用 getline() 从流(文件或标准输入)中获取所有行。这些行存储在我定义的结构内的 char *lineText 缓冲区中,名为 lineInText。
不幸的是,即使我在循环结束时释放了这个 char *lineText,我仍然得到一个 valgrind 报告,说使用 getline() 存在内存丢失。
我究竟做错了什么?

代码:
line的结构体及其相关函数:

typedef struct lineInText
{
    char *lineText;
    int indexOfLine;
    int numOfBytesFromStartToHere;
    bool isMatchInLine;
    bool isMatchInLineFromA;
} lineInText;


void initializeCurrentLine(lineInText *currentLine)
{
    currentLine->lineText = NULL;
    currentLine->numOfBytesFromStartToHere=0;
    currentLine->isMatchInLineFromA = false;
    currentLine->isMatchInLine = false;
    currentLine->indexOfLine = 0;
}

void FillLineStruct(lineInText *currentLine, int lineIndex, int numOfBytes) {
    currentLine->indexOfLine = lineIndex;
    currentLine->isMatchInLine = false;
    currentLine ->isMatchInLineFromA = false;
    currentLine->numOfBytesFromStartToHere = numOfBytes;
}

void freeLine(lineInText **line)
{
    free((*line)->lineText);
    free(*line);
}

main() 和调用 getline() 的函数:

void receiveAndExecute(parsedCommandStruct *parsedCommand, FILE **stream)
{
    ssize_t lineSize = ZERO;
    lineInText *currentLine = NULL;
    int lineIndex = 1, counterForC = 0, linesAfterMatchCounter = 0, sumOfBytes = 0;
    currentLine = (lineInText *) malloc(sizeof(lineInText));
    initializeCurrentLine(currentLine);

    while (1)
    {
        readLine(stream, &lineSize, currentLine, lineIndex);
        FillLineStruct(currentLine, lineIndex, sumOfBytes);
        sumOfBytes = (int)lineSize + sumOfBytes;
        lineIndex++;
        if(lineSize<0)
            break;
        reportLineMatch(currentLine, *parsedCommand, &linesAfterMatchCounter);
        printLineToOutput(currentLine, parsedCommand, &counterForC, false);
    }
    printLineToOutput(currentLine, parsedCommand, &counterForC, true);
    freeLine(&currentLine);
}

int main(int argc, char* argv[])
{
    parsedCommandStruct *parsedCommand = NULL;
    FILE *filePtr = NULL;
    bool useFile = false;
    useFile = isUsingFile(argc, argv);
    createAndFillCommand(argc, argv, &parsedCommand);

    if (useFile)
    {
        filePtr = openFile(argv[argc-1]);
        receiveAndExecute(parsedCommand, &filePtr);
        fclose(filePtr);
    }
    else
    {
        receiveAndExecute(parsedCommand, &stdin);
    }
    freeParsedCommandStruct(parsedCommand);
    free(parsedCommand);
    return 0;
}

void readLine(FILE **stream, ssize_t *getLineResult, lineInText *currentLine,  int lineIndex) {
    ssize_t lineSize = ZERO;
    size_t lineBufSize = ZERO;
    lineSize = getline(&(currentLine->lineText), &lineBufSize, *stream);
    *getLineResult = lineSize;
}

valgrind 报告:

valgrind --quiet --leak-check=yes ./my_grep bla bla | diff bla -==1878== 120 bytes in 1 blocks are definitely lost in loss record 1 of 1
==1878==    at 0x402C17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1878==    by 0x40A9FD7: getdelim (iogetdelim.c:62)
==1878==    by 0x40A6EB1: getline (getline.c:32)
==1878==    by 0x8048E79: readLine (in /home/user/Downloads/my_grep/my_grep)
==1878==    by 0x80493EF: receiveAndExecute (in /home/user/Downloads/my_grep/my_grep)
==1878==    by 0x804952A: main (in /home/user/Downloads/my_grep/my_grep)
==1878==

提前致谢

【问题讨论】:

  • 您应该将缓冲区的大小传递给getline,但您传递的是ZERO(为什么是ZERO?如果您的意思是0,那么请输入0...无论如何)。试试:lineSize = getline(&amp;(currentLine-&gt;lineText), getLineResult, *stream); 查看getline() 的手册。如果你传递的缓冲区太小,它会realloc它。
  • 建议:在freeLine函数中,考虑在最后加上*line = 0,这样调用者指向内存的指针已经被NULL'd out,没有机会了在意外重用。这并没有影响手头的问题,但这是进入 re: C 中的内存管理的一个非常好的习惯。

标签: c memory-leaks valgrind getline


【解决方案1】:

当您调用getline 时,lineBufSize 的值为 0。这意味着该函数认为缓冲区的长度为 0 字节。这对于第一次迭代是可以的,但在随后的迭代中会导致存储在currentLine-&gt;lineText 中的现有指针被抛出,从而导致内存泄漏。

您需要在结构中添加一个字段来跟踪缓冲区的当前大小并将其传递给getline

typedef struct lineInText
{
    char *lineText;
    int lineTextLen;    // keep track of the size of lineText
    int indexOfLine;
    int numOfBytesFromStartToHere;
    bool isMatchInLine;
    bool isMatchInLineFromA;
} lineInText;

void initializeCurrentLine(lineInText *currentLine)
{
    currentLine->lineText = NULL;
    currentLine->lineTextLen = 0;   // initialize buffer length to 0
    currentLine->numOfBytesFromStartToHere=0;
    currentLine->isMatchInLineFromA = false;
    currentLine->isMatchInLine = false;
    currentLine->indexOfLine = 0;
}

void readLine(FILE **stream, ssize_t *getLineResult, lineInText *currentLine,  int lineIndex) {
    ssize_t lineSize = ZERO;
    lineSize = getline(&(currentLine->lineText), &(currentLine->lineTextLen), *stream);
    *getLineResult = lineSize;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2016-08-31
    • 2016-04-25
    • 2012-01-27
    • 2014-04-09
    • 1970-01-01
    相关资源
    最近更新 更多