LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   getline throwing uninitialized value in valgrind (https://www.linuxquestions.org/questions/programming-9/getline-throwing-uninitialized-value-in-valgrind-4175729070/)

jmgibson1981 09-18-2023 03:12 PM

getline throwing uninitialized value in valgrind
 
Relavant code.

Code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jmgeneral.h>

#define TESTFILE "testfile.txt"

int line_num_chars(char * str);

int main()
{

  FILE * file = fopen(TESTFILE, "r");
  int max_chars = 0;
  int len = 0;
  char * buffer = NULL;
  bool keepgoing = true;

  while (keepgoing) {
    char * tempbuf = getline_mem_alloc(file);
    // allocate second memory. trying to make valgrind happy
    buffer = allocate_string_mem(tempbuf);

    // clear temp buffer asap to limit memory usage
    free(tempbuf);
    tempbuf = NULL;

    len = strlen(buffer);

    if (len > max_chars) {
      max_chars = len;
    }

    free(buffer);
    buffer = NULL;

    if (feof(file)) {
      keepgoing = false;
    }
  }

  fclose(file);
  file = NULL;

  printf("total top = %d\n", max_chars);
  return(0);
}

Code:

char * getline_mem_alloc(FILE * file)
{
  assert(file);

  // declare & initialize
  size_t buflen = 0;
  char * buffer = NULL;
  buflen = getline(&buffer,
                  &buflen,
                  file);

  // return buffer
  return(buffer);
}

Code:

char * allocate_string_mem(const char * str)
{
  assert(str);
  int chars = 0;

  char * retstr = (char*)malloc(strlen(str) * sizeof(char) + 1);
  for (int i = 0; i <= strlen(str); i++) {
    retstr[i] = '\0';
    chars++;
  }
  strncpy(retstr,
          str,
          chars);
  assert(retstr);
  return(retstr);
}

Output

Code:

valgrind -s --leak-check=full --track-origins=yes ./a.out
==48843== Memcheck, a memory error detector
==48843== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==48843== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==48843== Command: ./a.out
==48843==
==48843== Conditional jump or move depends on uninitialised value(s)
==48843==    at 0x48467E5: __strlen_sse2 (vg_replace_strmem.c:496)
==48843==    by 0x48543B2: allocate_string_mem (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x109205: main (in /home/jason/Documents/a.out)
==48843==  Uninitialised value was created by a heap allocation
==48843==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==48843==    by 0x48DFBAE: getdelim (iogetdelim.c:62)
==48843==    by 0x4853C79: getline_mem_alloc (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x1091F5: main (in /home/jason/Documents/a.out)
==48843==
==48843== Conditional jump or move depends on uninitialised value(s)
==48843==    at 0x4846DF3: __strncpy_sse2_unaligned (vg_replace_strmem.c:602)
==48843==    by 0x48543E7: allocate_string_mem (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x109205: main (in /home/jason/Documents/a.out)
==48843==  Uninitialised value was created by a heap allocation
==48843==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==48843==    by 0x48DFBAE: getdelim (iogetdelim.c:62)
==48843==    by 0x4853C79: getline_mem_alloc (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x1091F5: main (in /home/jason/Documents/a.out)
==48843==
total top = 29
==48843==
==48843== HEAP SUMMARY:
==48843==    in use at exit: 0 bytes in 0 blocks
==48843==  total heap usage: 13 allocs, 13 frees, 6,274 bytes allocated
==48843==
==48843== All heap blocks were freed -- no leaks are possible
==48843==
==48843== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
==48843==
==48843== 1 errors in context 1 of 2:
==48843== Conditional jump or move depends on uninitialised value(s)
==48843==    at 0x4846DF3: __strncpy_sse2_unaligned (vg_replace_strmem.c:602)
==48843==    by 0x48543E7: allocate_string_mem (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x109205: main (in /home/jason/Documents/a.out)
==48843==  Uninitialised value was created by a heap allocation
==48843==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==48843==    by 0x48DFBAE: getdelim (iogetdelim.c:62)
==48843==    by 0x4853C79: getline_mem_alloc (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x1091F5: main (in /home/jason/Documents/a.out)
==48843==
==48843==
==48843== 1 errors in context 2 of 2:
==48843== Conditional jump or move depends on uninitialised value(s)
==48843==    at 0x48467E5: __strlen_sse2 (vg_replace_strmem.c:496)
==48843==    by 0x48543B2: allocate_string_mem (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x109205: main (in /home/jason/Documents/a.out)
==48843==  Uninitialised value was created by a heap allocation
==48843==    at 0x48407B4: malloc (vg_replace_malloc.c:381)
==48843==    by 0x48DFBAE: getdelim (iogetdelim.c:62)
==48843==    by 0x4853C79: getline_mem_alloc (in /usr/local/lib/libjmgeneral.so)
==48843==    by 0x1091F5: main (in /home/jason/Documents/a.out)
==48843==
==48843== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

I've tried many variations thinking it was something with my functions. I can do this via fgets no problem no errors. but something about my getline here. I've googled, seems to be an occasional problem but haven't found a solution that works yet.

NevemTeve 09-18-2023 03:49 PM

Code:

char * allocate_string_mem(const char * str)
{
  assert(str);
  int chars = 0;

  char * retstr = (char*)malloc(strlen(str) * sizeof(char) + 1);
  for (int i = 0; i <= strlen(str); i++) {
    retstr[i] = '\0';
    chars++;
  }
  strncpy(retstr,
          str,
          chars);
  assert(retstr);
  return(retstr);
}

Please optimalize this function as it is extremely slow. (When it is done, simple drop it, there is a standard strdup function.)

astrogeek 09-18-2023 07:49 PM

Valgrind knows the memory has been allocated within getline() and assigned to pointer buffer, but seems unaware that it has been written by getline(). Any attempt to read it produces a valgrind error, but you can write to it and once you do the program completes and valgrind says all is OK. For example, add strcpy(buffer,"some text") immediately after the call to getline() (be sure not to exceed buflen).

I am not a frequent valgrind user so cannot say whether this is to be expected or why it happens. My searches turned up other odd valgrind behaviors with getline, some version dependent, but not this exactly.

Hope it helps.

jmgibson1981 09-18-2023 09:08 PM

Ok. I tried a few more things. And I dumped those 2 alloc functions I had written and replaced with strdup in my library.

Thank you both.

It works fine if I don't try to operate on the tempbuf return. No errors. But as soon as I want to run an operation on it, strlen or whatever so far seems to toss that error.

NevemTeve 09-18-2023 10:10 PM

It might give more information, if you compile your shared library with option `-g`.
Or for debugging you could directly link your rutins into the executable.

PS: don't do this with 'buflen':
Code:

buflen = getline(&buffer, &buflen, file);
Instead add error-checks after `fopen` and `getline`

jmgibson1981 09-18-2023 11:41 PM

Ok done. The main function is just me fiddling around. I normally run tests on file ops. I did replace that buflen thing with a test with error message & bail out on fail.

NevemTeve 09-19-2023 12:45 AM

E.g.:
Code:

ssize_t strLen = getline(&buffer, &buflen, file);

astrogeek 09-19-2023 03:25 PM

Could not get this off my mind as I did not really understand it on first look, and knew it, and it did not seem reasonable that valgrind would miss an initialization.

NevemTeve is on the right track. You need to test for unsuccessful call to getline(...), it returns -1 for both errors and for EOF, and it is the EOF that is causing the problem.

You are not using buflen or the returned character count, so just test for -1.

The acual cause of the valgrind error is, even though unsuccessful or EOF, a buffer will have been allocated and needs to be free()d and not further used.

So, along with the change from allocate_string_mem() to strdup() and a test of returned pointer, this should fix it up properly:

Code:

char * getline_mem_alloc(FILE * file)
{
  assert(file);

  size_t buflen = 0;
  char * buffer = NULL;
  if(getline(&buffer,
                  &buflen,
                  file)==-1)
        {
        free(buffer);
        buffer = NULL;
        }
  return(buffer);
}

Note: I have not looked at your github changes so above applies to your originally posted code.

jmgibson1981 09-19-2023 04:58 PM

Git pushed. I am very grateful to you folks. Works no errors now.

*EDIT* in a previous post I mentioned about needing to research return codes. its getting more necessary quickly.

astrogeek 09-19-2023 05:02 PM

You are very welcome, and thanks for the opportunity to improve my poor valgrind skills!


All times are GMT -5. The time now is 03:01 PM.