I am writing a grep program in C. I am using getline() inside a while loop to get all lines from stream (file or stdin). The lines are stored into char *lineText buffer inside a struct i defined, named lineInText.
unfortunately even though I am freeing this char *lineText at the end of the loop i still get a valgrind report says that there is a memory loss using getline().
What am I doing wrong?
the code:
the struct of line and its related functions:
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);
}
the main() and the functions calling 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(¤tLine);
}
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;
}
the valgrind report:
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==
thanks in advance
When you call getline
, lineBufSize
has a value of 0. This means the function thinks the buffer is 0 bytes in length. This is OK for the first iteration but on subsequent iterations is results in the existing pointer stored in currentLine->lineText
getting thrown out, causing the memory leak.
You need to add a field to your struct to keep track of the current size of the buffer and pass that to 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;
}