Home > Enterprise >  Why do I have to malloc the buffer each time I call 'getline' on a new file pointer?
Why do I have to malloc the buffer each time I call 'getline' on a new file pointer?

Time:06-28

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).

  • Related