Where is the uninitialized value in this function? - c

I am running a debug-version of my C binary within valgrind, which returns numerous errors of the sort Conditional jump or move depends on uninitialised value(s).
Using the symbol table, valgrind tells me where to look in my program for this issue:
==23899== 11 errors in context 72 of 72:
==23899== Conditional jump or move depends on uninitialised value(s)
==23899== at 0x438BB0: _int_free (in /foo/bar/baz)
==23899== by 0x43CF75: free (in /foo/bar/baz)
==23899== by 0x4179E1: json_tokener_parse_ex (json_tokener.c:593)
==23899== by 0x418DC8: json_tokener_parse (json_tokener.c:108)
==23899== by 0x40122D: readJSONMetadataHeader (metadataHelpers.h:345)
==23899== by 0x4019CB: main (baz.c:90)
I have the following function readJSONMetadataHeader(...) that calls json_tokener_parse():
int readJSONMetadataHeader(...) {
char buffer[METADATA_MAX_SIZE];
json_object *metadataJSON;
int charCnt = 0;
...
/* fill up the `buffer` variable here; basically a */
/* stream of characters representing JSON data... */
...
/* terminate `buffer` */
buffer[charCnt - 1] = '\0';
...
metadataJSON = json_tokener_parse(buffer);
...
}
The function json_tokener_parse() in turn is as follows:
struct json_object* json_tokener_parse(const char *str)
{
struct json_tokener* tok;
struct json_object* obj;
tok = json_tokener_new();
obj = json_tokener_parse_ex(tok, str, -1);
if(tok->err != json_tokener_success)
obj = (struct json_object*)error_ptr(-tok->err);
json_tokener_free(tok);
return obj;
}
Following the trace back to readJSONMetadataHeader(), it seems like the uninitialized value is the char [] (or const char *) variable buffer that is fed to json_tokener_parse(), which in turn is fed to json_tokener_parse_ex().
But the buffer variable gets filled with data and then terminated before the json_tokener_parse() function is called.
So why is valgrind saying this value is uninitialized? What am I missing?

It looks from the valgrind error report as if your application is statically linked (in particular, free appears to be in the main executable, and not libc.so.6).
Valgrind will report bogus errors for statically linked applications.
More precisely, there are intentional "don't care" errors inside libc. When you link the application dynamically, such errors are suppressed by default (via suppressions file that ships with Valgrind).
But when you link your application statically, Valgrind has no clue that the faulty code come from libc.a, and so it reports them.
Generally, statically linking applications on Linux is a bad idea (TM).
Running such application under Valgrind: doubly so: Valgrind will not be able to intercept malloc/free calls, and will effectively catch only uninitialized memory reads, and not heap buffer overflows (or other heap corruption bugs) that it is usually good at.

I don't see charCnt initialized.
To see if it comes from buffer, simply initialize it with = {0}, this also would make your null termination of the buffer obsolete.

Have a look in json_tokener_parse_ex() which you don't show. It's likely it's trying to free something that's not initialized.

buffer[charCnt - 1] = '\0';
This will at least fail if charCnt happens to be zero.

Related

APR memory not freed after pool destroy

apr_pool_t *pool;
char *a;
char *b;
apr_pool_create(&pool, NULL);
a = (char *) apr_palloc(pool, 10);
strcpy(a, "hello");
printf("a is %s\n", a);
apr_pool_destroy(pool);
apr_terminate();
b = (char *) apr_palloc(pool, 10);
strcpy(b, "world");
printf("b is %s\n", b);
I'm new to libapr, from the document it said
Destroy the pool. This takes similar action as apr_pool_clear() and then frees all the memory.
but actually it's not, and I can still use apr_palloc to alloc memory from a destroyed pool? so my question is how can I actually free the memory and how can I actually destroy the pool object
You are invoking Undefined Behavior in at least two places.
I compiled on my linux (Mint a derived of Ubuntu), gcc 7.4. Your program crashes at the first apr_pool_create because you did not invoke the appropriate initialization functions (e.g. apr_initialize), see https://apr.apache.org/docs/apr/1.6/group__apr__library.html .
Here is the Valgrind trace:
==7158== Process terminating with default action of signal 11 (SIGSEGV)
==7158== Access not within mapped region at address 0x30
==7158== at 0x4E595F0: apr_pool_create_ex (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.6.3)
==7158== by 0x1088EB: main (in /home/user/apr/test)
=
Once that issue is fixed, you get the following program (note: I do not know whether apr_initialize or apr_app_initialize is appropriate for your use case).
apr_pool_t *pool;
char *a;
char *b;
apr_initialize(); // You need this or apr_app_initialize
apr_pool_create(&pool, NULL);
a = (char *) apr_palloc(pool, 10);
strcpy(a, "hello");
printf("a is %s\n", a);
apr_pool_destroy(pool);
apr_terminate();
b = (char *) apr_palloc(pool, 10);
strcpy(b, "world");
printf("b is %s\n", b);
The above code crashes in the second apr_palloc with the following Valgrind trace because you are accessing memory that was freed most likely as a consequence of apr_pool_destroy
a is hello
==7196== Invalid read of size 8
==7196== at 0x4E58A62: apr_palloc (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.6.3)
==7196== by 0x1089AF: main (in /home/user/apr/test)
==7196== Address 0x402d080 is not stack'd, malloc'd or (recently) free'd
==7196==
Removing the last lines
b = (char *) apr_palloc(pool, 10);
strcpy(b, "world");
printf("b is %s\n", b);
allow the program to terminate correctly and Valgrind shows no errors.
So it looks like apr_pool_destroy is working correctly, you were simply accessing memory you were not supposed to have access to and you did not experience a crash: Undefined Behavior is sneaky, your program can run for years without showing any problem, and then, one day it crashes.
For completeness, I compiled with the following command (the code was in test.c):
gcc -Wall test.c $(apr-1-config --cflags --cppflags --includes --link-ld) -o test
I suggest that you should use tools like Valgrind (http://www.valgrind.org/) to detect these kind of issues.
User Eliyahu Machluf (thanks) makes the point that APR provides facilities to debug memory allocation, from http://download.vikis.lt/manual/developer/debugging.html
Allocation Debugging
ALLOC_DEBUG
Debugging support: Define this to enable code which helps detect re-use of
free()d memory and other such nonsense.
The theory is simple. The FILL_BYTE (0xa5) is written over
all malloc'd memory as we receive it, and is written over everything
that we free up during a clear_pool. We check that blocks on the free
list always have the FILL_BYTE in them, and we check during palloc()
that the bytes still have FILL_BYTE in them. If you ever see garbage
URLs or whatnot containing lots of 0xa5s then you know something used
data that's been freed or uninitialized.
As pointed out previously, apr_initialize is a pre-requisite to using the pools. But the opposite of initialising the required data structures before use is tearing them down at the other end. That's what apr_terminate does. It makes no sense to try to use the library for memory allocation after you've taken away the stuff that it relies on.
If you run your program under valgrind as is (with the addition of the initialize) and then compare it to a second version where the apr_terminate is moved to just before the end of your code you should see a clear difference.

Why segfaults occur with string.h functions?

With the same command in my coworker's PC, my program works without the problem.
But in my PC, the program crashes with segfault;
GDB backtrace at core reads as follows:
#0 strrchr () at ../sysdeps/x86_64/strrchr.S:32
32 ../sysdeps/x86_64/strrchr.S: no such file or directory
(gdb) bt
#0 strrchr () at ../sysdeps/x86_64/strrchr.S:32
#1 0x00007f10961236d7 in dirname (path=0x324a47a0 <error: Cannot access memory at address 0x324a47a0>) at dirname.c:31
I'm already compiling the executable with -g -ggdb options.
Odd thing is that.. with valgrind the program works without error in my PC as well.
How can I solve the problem? I've observed that the errors occur only with strrchr, strcmp, strlen, ... string.h functions.
+Edit: the gdb backtrace indicates that the program crashes here:
char* base_dir = dirname(get_abs_name(test_dir));
where get_abs_name is defined as
char* get_abs_name(char* dir) {
char abs_path[PATH_MAX];
char* c = malloc(PATH_MAX*sizeof(char));
realpath(dir, abs_path);
strcpy(c, abs_path);
return c;
}
+Edit2: 'dir' is a path of certain file, like '../program/blabla.jpg'.
Using valgrind,
printf("%s\n", dir)
normally prints '/home/frozenca/path_to_program'.
I can't guess why the program crashes without valgrind..
We cannot know for sure without a Minimal, Complete, and Verifiable example. Your code looks mostly correct (albeit convoluted), except you do not check for errors.
char* get_abs_name(char* dir) {
char abs_path[PATH_MAX];
char* c = malloc(PATH_MAX*sizeof(char)); /* this may return NULL */
realpath(dir, abs_path); /* this may return NULL */
strcpy(c, abs_path);
return c;
}
Now, how could this lead to an error like you see? Well, if malloc returns NULL, you'll get a crash right away in strcpy. But if realpath fails:
The content of abs_path remains undefined.
So strcpy(c, abs_path) will copy undefined content. Which could lead to it copying just one byte if abs_path[0] happens to be \0. But could also lead to massive heap corruption. Which happens depends on unrelated conditions, such as how the program is compiled, and whether some debugging tool such as valgrind is attached.
TL;DR: get into the habit of checking every function that may fail.
char* get_abs_name(char* dir) {
char abs_path[PATH_MAX];
char* c = malloc(PATH_MAX*sizeof(char));
if (!c) { return NULL; }
if (!realpath(dir, abs_path)) {
free(c);
return NULL;
}
strcpy(c, abs_path);
return c;
}
Or, here, you can simplify it alot assuming a GNU system or POSIX.1-2008 system:
char * get_abs_name(const char * dir) {
return realpath(dir, NULL);
}
Note however that either way, in your main program, you also must check that get_abs_name() did not return NULL, otherwise dirname() will crash.
Drop your function entirely and use the return value of realpath(dir, NULL) instead.
Convert type
char* c = malloc(PATH_MAX*sizeof(char));
Thanks!

cJSON memory leak

I use cJSON in my program to convert my values to JSON and write it to file. Here is the example of my code:
void writeStructToFile(IOPipe this, struct structtype somevalues) {
cJSON *jout = cJSON_CreateObject();
cJSON_AddItemToObject(jout, "V1", cJSON_CreateNumber(somevalues.v1));
cJSON_AddItemToObject(jout, "V2", cJSON_CreateNumber(somevalues.v2));
fprintf(this->outstream, "%s", cJSON_Print(jout));
cJSON_Delete(jout);
}
Works great, but after some time I found that Linux(embedded) kills my program because of abnormal memory use or device(on Cortex A8) just hangs. After debug I found, that leak appears exactly in this function even though I delete the pointer at the end. Could anyone see that leak?
Initially I thought that it might be FILE I/O's internal buffers. But these are flushed automatically when they become too big.
The real leak is that cJSON_Print allocates memory: a char array. You must free this after you're done:
char* text = cJSON_Print(jout);
fprintf(this->outstream, "%s", text);
free(text); // As suggested by PaulPonomarev.
cJSON_Delete(jout);
For a char* allocated cJSON_Print, it is said to use cJSON_FreePrintBuffer.

trying to free allocated memory generate heap error

I'm dealing with a strange errors in code which i wrote in c.
this is the place where the error occur:
char* firstChar = (char*) malloc(ONE_CHAR_STRING);
if (!firstChar) {
*result = MTM_OUT_OF_MEMORY;
return false;
}
if (command != NULL) {
strcpy(firstChar, command);
firstChar[1] = '\0';
}
free(firstChar);
'command' is a string, and ONE_CHAR_STRING defines in the program, (ONE_CHAR_STRING= 2).
the error which appear when the program get into the 'free' function is:
warning: Heap block at 00731528 modified at 00731532 past requested size of 2
this error strangely append only on my PC/eclipse on windows. when i run the code in linux it doesn't prompt this error and works(the specific part) fine.
what could be the reason?
another question again about memory errors, how it is possibly that my program(without this part) works fine on windows, but in linux their is a problem in one of my memory allocations?
I can't write down here the code cause it's too long (and gdb doesn't gives me the lines of where the error occur).. the question is about the possibility and what could be the reasons for it.
Thanks, Almog.
you can use another string copy function to avoid overflow:
strncpy(firstChar,command,ONE_CHAR_STRING);
strcpy may overlap to copy firstChar if command string length is greater than ONE_CHAR_STRING or not null terminated that lead you to strange behavior. You can safely copy command string to firstChar by assign firstChar[0] = command[0]; firstChar[1] = '\0'
If your compiler for both Linux and Windows is gcc (MinGW in Windows) use -fstack-protector as compiler parameter to help you to debug function such as strcpy buffer overflow.

Valgrind errors even though all heap blocks were freed

I have recently developed a habit of running all of my programs through valgrind to check for memory leaks, but most of its results have been a bit cryptic for me.
For my latest run, valgrind -v gave me:
All heap blocks were freed -- no leaks are possible
That means my program's covered for memory leaks, right?
So what does this error mean? Is my program not reading certain memory blocks correctly?
ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 14 from 9)
1 errors in context 1 of 1:
Invalid read of size 4
at 0x804885B: findPos (in /home/a.out)
by 0xADD918: start_thread (pthread_create.c:301)
by 0xA26CCD: clone (clone.S:133)
Address 0x4a27108 is 0 bytes after a block of size 40 alloc'd
at 0x4005BDC: malloc (vg_replace_malloc.c:195)
by 0x804892F: readInput (in /home/a.out)
by 0xADD918: start_thread (pthread_create.c:301)
by 0xA26CCD: clone (clone.S:133)
used_suppression: 14 dl-hack3-cond-1
Also, what are the so-called "suppressed" errors here?
This seems obvious ... but it might be worth pointing out that the "no leaks are possible" message does not mean that your program cannot leak; it just means that it did not leak in the configuration under which it was tested.
If I run the following with valgrind with no command line parameters, it informs me that no leaks are possible. But it does leak if I provide a command line parameter.
int main( int argc, char* argv[] )
{
if ( argc > 1 )
malloc( 5 );
printf( "Enter any command line arg to cause a leak\n" );
}
Yes, you are greatly covered, don't
think that valgrind easily can miss
a leak in user code
your error means that you probably
have a +1 error in indexing an array
variable. the lines that valgrind
tell you should be accurate, so you
should easily find that, provided you compile all your code with -g
suppressed errors are usually from
system libraries, which sometimes have small leaks or undectable things like the state variables of threads. your manual page should list the suppression file that is used by default
Checking for memory leaks is one reason to use valgrind, but I'd say a better reason is to find more serious errors in your code, such as using an invalid array subscript or dereferencing an uninitialized pointer or a pointer to freed memory.
It's good if valgrind tells you that the code paths you exercised while running valgrind didn't result in memory leaks, but don't let that cause you to ignore reports of more serious errors, such as the one you're seeing here.
As other have suggested, rerunning valgrind after compiling with debug information (-g) would be a good next step.
If you are getting below error:-
"Invalid read of size 4"
Are you freeing memory before and then go to next argument?
I am also getting error because in linked list I am freeing memory first and then go to next element.
Below is my code snippet where I am getting error -
void free_memory(Llist **head_ref)
{
Llist *current=NULL;
current=*head_ref;
while(*head_ref != NULL)
{
current=*head_ref;
free(current);
current=NULL;
(*head_ref)=(*head_ref)->next;
}
}
After changes below is my code snippet -
void free_memory(Llist **head_ref)
{
Llist *current=NULL;
current=*head_ref;
while(*head_ref != NULL)
{
current=*head_ref;
(*head_ref)=(*head_ref)->next;
free(current);
current=NULL;
}
}

Resources