I have a daemon written in C that reads a file every INTERVAL
seconds line by line and does some work on each line if it matches the criteria. I can't leave the file open since the file is being accessed and modified by another API, so this is a snippet of the code to show the issue:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define INTERVAL 5
int main(int argc, char *argv[])
{
size_t len = 100;
FILE *fp;
char *line = NULL;
line = malloc(len * sizeof(char));
size_t read;
int iteration = 1;
while (1)
{
printf("iteration %d\n", iteration );
fp = fopen("input.txt", "r ");
if (fp == NULL)
exit(EXIT_FAILURE);
while ((read = getline(&line, &len, fp)) != -1)
{
printf("line is: %s\n", line);
// Do some more work with the data.
// If the password has expired remove it from the file.
}
fclose(fp);
if (line)
{
free(line);
}
sleep(INTERVAL);
}
}
When running this code, it results in this:
iteration 1
line is: 1656070481 qwerty12345
line is: 1656070482 qwerty
iteration 2
line is: 1656070481 qwerty12345
line is: 1656070482 qwerty
daemon(37502,0x1027e4580) malloc: *** error for object 0x600003ca8000: pointer being freed was not allocated
daemon(37502,0x1027e4580) malloc: *** set a breakpoint in malloc_error_break to debug
zsh: abort ./daemon
So the problem is in this line:
if (line)
{
free(line);
}
It looks like somehow the pointer is being deallocated somewhere inside the while loop. So, to solve this, I have to call the malloc
function at the start of the while(1)
loop to reallocate the memory with each iteration, like so:
while (1)
{
printf("iteration %d\n", iteration );
line = malloc(len * sizeof(char));
This solves the issue, but I want to understand why the issue happened in the first place. Why is the pointer being deallocated after the second iteration?
CodePudding user response:
have a daemon written in C
Then call daemon(3).
so the problem is in this line:
if (line){ free(line); }
Yes. So you need to clear line
and code
if (line) {
free(line);
line = NULL;
len = 0;
}
On the next loop, line
will be NULL
and you won't (incorrectly) free
it twice.
(I won't bother free
-ing inside the loop, but this is just my opinion)
Of course, before getline
you want to allocate line
, so before
while ((read = getline(&line, &len, fp)) != -1)
code:
if (!line) {
line = malloc(100);
if (line)
len = 100;
};
Consider using valgrind and in some cases Boehm conservative GC (or my old Qish GC downloadable here). You may then have to avoid getline
and use simpler and lower-level alternatives (e.g. read(2) or simply fgetc(3) ...)
Read the GC handbook.
Perhaps use Frama-C on your source code.
(Consider also using Rust or Go or C or Ocaml or Common Lisp/SBCL to recode entirely your daemon)
On Linux, see also inotify(7).