Program aborts after freeing previously allocated memory - c

I'll ask you for some help with a really really simple program which implements a search planning algorithm. Well, the problem I got is a little weird for me: after allocating memory for a simple array of characters declared locally in a function, I work over this array, it has all the expected behaviors and everything goes ok, but when I call the free() function to this array before the function ends, the program stops and abort. If someone with some experience about this problem (or not...) could help me, i'd be really thankful. Well, here follows some lines of a "simulated" code to show what I'm talking about (it's not exactly what's written, but the :
char* v_AllTheWorld
char* v_ReadALineOfTheWorld;
v_AllTheWorld = malloc(COLUMNS * LINES * sizeof(char)); /*LINES and COLUMNS are defined constants*/
if(v_AllTheWorld == NULL)
{
fprintf(stderr, "..."); //etc, etc.
exit(1);
}
v_ReadALineOfTheWorld = malloc(COLUMNS * sizeof(char)); /*the "sizeof(char)" looks useless, but there's no point in talking about that here, i guess.*/
if(v_ReadALineOfTheWorld == NULL)
{
fprintf(stderr, "..."); //etc, etc.
exit(1);
}
while(/*some_condition (number of lines to be read)*/)
{
//read data string from stream and stores in v_ReadALineOfTheWorld (fscanf);
//appends the read data to v_AllTheWorld (strncat);
}
free(v_ReadALineOfTheWorld);
/*The program is stopping right after this call in the debug.*/
return v_AllTheWorld;
I didn't put the head of the function, the declaration of it, and I didn't represent the stream or how the data is manipulated in details, but no other calls of "malloc" or "free" are made and all the code that is written is executed unconditionally (out of any "if" or similar). Course, the last bahavior doesn't include the allocation tests, but you got what I'm saying.
So, well, I hope I did it right asking this way, I hope I detailed the problem the right way and I hope you may help me.
Oh, I almost forgot that: as you probably noticed, the program is in C.

This could happen if you are writing outside the bounds of v_ReadALineOfTheWorld. Some malloc libraries store info about the mallocd region in a wrapper around the region, and if you corrupt that info free could crash.

Related

sprintf() prints string to (m)allocated array, although it should be to small

I've been searching the net including stackoverflow for hours and didn't find any answer which suits my problem - maybe because it's not a real problem since the program works...but it shouldn't. Sounds strange? It is - at least to me.
It's part of a task for university. The task is to allocate memory for a char array, then print a string to the array using sprintf() and finally printing the array with printf(). For memory allocation malloc() is to be used (I know there a better ways, but we have to use exactly these functions).
That's what I've got:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
// Declare char array
char *string;
/* Allocate memory for string of certain length
The 1 is only to show what's wrong. I'm aware of the actual size needed */
if( (string = malloc( 1 * sizeof(char) ) ) == NULL )
{
perror("malloc failed to allocate n chars!");
exit(1);
}
/* Print string to previously allocated memory. Now I would expect an error due to too few bytes allocated */
sprintf(string, "Too many characters here...");
// Print string to command line
printf("%s\n", string);
return 0;
}
So far it works: It compile without any notice using gcc -Wall -std=c99 as well on Ubuntu as on Mac OSX.
BUT
The problem is that it shouldn't. As you might have noticed I allocated to few bytes for the string I am writing to the array. Still it works, no matter how long the string is (tried up to 1000 chars) or how many bytes I allocate.
Wouldn't care about it, if the university's automated testing unit wouldn't mark it as wrong. It says the program is not reading from the allocated array. That's why I assume, that sprintf puts the string anywhere but in the allocated array. But I can't explain how this could be possible.
I would be deeply grateful if you guys know what I'm doing wrong.
Thanks in advance!
------ UPDATE ------
As Mike pointed out I'm not using free(string) in this snippet (thanks the hint!). In the actual program I placed free(string) after the printf(). But when I try to print string after that statement again -> it's printed as if nothing happened! How is that possible?
The problem is with the assertion "The problem is that it shouldn't." or "expect an error".
/* Now I would expect an error due to too few bytes allocated */
sprintf(string, "Too many characters here...");
When code does something is should not, like writing beyond allocated memory space, C does not defined what should happen. Therefore it is Undefined Behavior (UB). To expect an error requires a defined behavior on C's part.
UB means anything may happen. The code is not required to check and complain that an attempt to access outside allocated memory occurred.
C provides you with lots of rope fro code to do all sorts of things quickly
- including enough rope for code to hang itself.
Given that sprintf() is prone to writing out of bounds, code could have used snprintf() and checked its results. snprintf() will not over-write the given size of the buffer.
char *string;
size_t size = 1; // or whatever
string = malloc(size);
...
int n = snprintf(string, size, "Too many characters here...");
if (n < 0 || n >= size) return Error_code;
...
printf("%s\n", string);
Overwriting the end of a malloc'd array is likely to mess things up, but exactly what gets messed up is a matter of chance. That it happens not to fail in a simple test is not surprising, especially since your program exited shortly after committing the miseed. The string that's written is, in itself, intact and valid -- it's only other things using that area of memory that may suffer. That doesn't mean it will work in a more complex circumstance.
I just tested the code on the university's server again - the SAME code as before - and now it works. I have absolutely no idea why, certainly there was an error in the testing unit.
So there was no error in my code. But at least testing it with wrong parameters now taught me something important (what you guys pointed out):
Undefined behavior can also be that everything appears to work fine; although it shouldn't.
So from this point of view you were right. This is very similar to the posted topics. It was me approaching the problem with wrong expectations.
Thank you!
The problem is that you're assuming that there should be something wrong and that the compiler should tell you that it's wrong.
The syntax is correct, but the semantics aren't - the compiler can only tell you so much. sprint() will print what you want it to, but what all it writes to in memory varies.
Consider using snprintf()

C: dynamic char-array crashes heap

I have yet again a question about the workings of C. (ANSI-C compiled by VS2012)
I am refactoring a standalone program (.exe) into a .dll. This works fine so far but I stumble accross problems when it comes to logging. Let me explain:
The original program - while running - wrote a log-file and printed information to the screen. Since my dll is going to run on a webserver, accessed by many people simultaneously there is
no real chance to handle log-files properly (and clean up after them)
no console-window anyone would see
So my goal is to write everything that would be put in the log-file or on the screen into string-like variables (I know that there are no strings in C) which I then can later pass on requet to the caller (also a dll, but written in C#).
Since in C such a thing is not possible:
char z88rlog;
z88rlog="First log-entry\n";
z88rlog+="Second log-entry\n";
I have two possibilities:
char z88rlog[REALLY_HUGE];
dynamically allocating memory
In my mind the first way is to be ignored because:
The potential waste of memory is rather enormous
I still may need more memory than REALLY_HUGE, thus creating a buffer overflow
which leaves me with the second way. I have done some work on that and came up with two solutions, either of which doesn't work properly.
/* Solution 1 */
void logpr(char* tmpstr)
{
extern char *z88rlog;
if (z88rlog==NULL)
{
z88rlog=malloc(strlen(tmpstr)+1);
strcpy(z88rlog,tmpstr);
}
else
{
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));
z88rlog=strcat(z88rlog,tmpstr);
}
}
In solution 1 (equal to solution 2 you will find) I pass my new log-entry through char tmpstr[255];. My "log-file" z88rlog is declared globally, so I need extern to access it. I then check if memory has been allocated for z88rlog. If no I allocate memory the size of my log-entry (+1 for my \0) and copy the contents of tmpstr into z88rlog. If yes I realloc memory for z88rlog in the size of what it has been + the length of tmpstr (+1). Then the two "string" are joined, using strcat. Using breakpoints an the direct-window I obtainded the following output:
z88rlog
0x00000000 <Schlechtes Ptr>
z88rlog
0x0059ef80 "start Z88R version 14OS"
z88rlog
0x0059ef80 "start Z88R version 14OS
opening file Z88.DYNÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍýýýý««««««««þîþîþîþ"
It shows three consecutive calls of logpr (breakpoint before strcpy/strcat). The indistinguable gibberish at the end results from memory allocation. After that VS gives out an error message that something caused the debugger to set a breakpoint in realloc.c. Because this obviously doesn't work I concocted my wonderful solution 2:
/* Solution 2 */
void logpr(char* tmpstr)
{
extern char *z88rlog;
char *z88rlogtmp;
if (z88rlog==NULL)
{
z88rlog=malloc(strlen(tmpstr)+1);
strcpy(z88rlog,tmpstr);
}
else
{
z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
z88rlogtmp=strcat(z88rlog,tmpstr);
free(z88rlog);
z88rlog=malloc(strlen(z88rlogtmp)+1);
memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
free(z88rlogtmp);
}
}
Here my aim is to create a copy of my log-file, free the originals' memory create new memory for the original in the new size and copy the contents back. And don't forget to free the temporary copy since it's allocated via malloc. This crashes instantly when it reaches free, again telling me that the heap might be broken.
So lets comment free for the time being. This does work better - much to my relief - but while building the log-string suddenly not all characters from z88rlogtmp get copied. But everything still works kind of properly. Until suddenly I am told again that the heap might be broken and the debugger puts a breakpoint at the end of _heap_alloc (size_t size) in malloc.c size has - according to the debugger - the value of 1041.
So I have 2 (or 3) ways I want to achieve this "string-growing" but none works. Might the error giving me the size point me to the conclusion that the array has become to big? I hope I explained well what I want to do and someone can help me :-) Thanks in advance!
irony on Maybee I should just go and buy some new heap for the computer. Does it fit in RAM-slots? Can anyone recomend a good brand? irony off
This is one mistake in Solution 1:
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr));
as no space is allocated for the terminating null character. Note that you must store the result of realloc() to a temporary variable to avoid memory leak in the event of failure. To correct:
char* tmp = realloc(z88rlog, strlen(z88rlog) + strlen(tmpstr) + 1);
if (tmp)
{
z88rlog = tmp;
/* ... */
}
Mistakes in Solution 2:
z88rlogtmp=malloc(strlen(z88rlog)+strlen(tmpstr+1));
/*^^^^^^^^^*/
it is calulating one less than the length of tmpstr. To correct:
z88rlogtmp=malloc(strlen(z88rlog) + strlen(tmpstr) + 1);
Pointer reassignment resulting in undefined behaviour:
z88rlogtmp=strcat(z88rlog,tmpstr);
/* Now, 'z88rlogtmp' and 'z88rlog' point to the same memory. */
free(z88rlog);
/* 'z88rlogtmp' now points to deallocated memory. */
z88rlog=malloc(strlen(z88rlogtmp)+1);
/* This call ^^^^^^^^^^^^^^^^^^ is undefined behaviour,
and from this point on anything can happen. */
memcpy(z88rlog,z88rlogtmp,strlen(z88rlogtmp)+1);
free(z88rlogtmp);
Additionally, if the code is executing within a Web Server it is almost certainly operating in a multi-threaded environment. As you have a global variable it will need synchronized access.
You seem to have many problems. To start with in your realloc call you don't allocate space for the terminating '\0' character. In your second solution you have strlen(tmpstr+1) which isn't correct. In your second solution you also use strcat to append to the existing buffer z88rlog, and if it's not big enough you overwrite unallocated memory, or over data allocated for something else. The first argument to strcat is the destination, and that is what is returned by the function as well so you loose the newly allocated memory too.
The first solution, with realloc, should work fine, if you just remember to allocate that extra character.
In solution 1, you would need to allocate space for terminating NULL character. Hence, the realloc should include one more space i.e.
z88rlog=realloc(z88rlog,strlen(z88rlog)+strlen(tmpstr) + 1);
In second solution, I am not sure of this z88rlogtmp=strcat(z88rlog,tmpstr); because z88rlog is the destination string. In case you wish to perform malloc only, then
z88rlogtmp=malloc(strlen(z88rlog)+1 // Allocate a temporary string
strcpy(z88rlogtmp,z88rlog); // Make a copy
free(z88rlog); // Free current string
z88rlog=malloc(strlen(z88rlogtmp)+ strlen(tmpstr) + 1)); //Re-allocate memory
strcpy(z88rlog, z88rlogtmp); // Copy first string
strcat(z88rlog, tmpStr); // Concatenate the next string
free(z88rlogtmp); // Free the Temporary string

malloc function crash

I have a problem with memory allocation using malloc.
Here is a fragment from my code:
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
It outputs "DEBUG 3",and then a error msgbox appears with this message:
The instruction at 0x7c9369aa referenced memory at "0x0000000". The
memory could not be read
For me such behavior is very strange.
What can be wrong here?
The application is single threaded.
I'm using mingw C compiler that is built in code::blocks 10.05
I can provide all the code if it is needed.
Thanks.
UPD1:
There is more code:
char *concat3(char *str1,char *str2,char *str3)
{
/*concatenate three strings and frees the memory allocated for substrings before*/
/* returns a pointer to the new string*/
int L=strlen(str1)+strlen(str2)+strlen(str3);
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
sprintf(s,"%s%s%s",str1,str2,str3);
free(str1);
free(str2);
free(str3);
return s;
}
UPD2:
It seems the problem is more complicated than i thought. Just if somebody has enough time for helping me out:
Here is all the code
Proj
(it is code::blocks 10.05 project,but you may compile the sources without an ide ,it is pure C without any libraries):
call the program as
"cbproj.exe s.pl" (the s.pl file is in the root of the arhive)
and you may see it crashes when it calls the function "malloc" that is on the 113th line of "parser.tab.c"(where the function concat3 is written).
I do the project in educational purpouses,you may use the source code without any restrictions.
UPD3:
The problem was that it was allocated not enough memory for one of the strings in program ,but the it seemed to work until the next malloc.. Oh,I hate C now:)
I agree with the comments about bad coding style,need to improve myself in this.
The problem with this exact code is that when malloc fails, you don't return from the function but use this NULL-pointer further in sprintf call as a buffer.
I'd also suggest you to free memory allocated for str1, str2 and str3 outside this function, or else you might put yourself into trouble somewhere else.
EDIT: after running your program under valgrind, two real problems revealed (in parser.tab.c):
In yyuserAction,
char *applR=(char*)malloc(strlen(ruleName)+7);
sprintf(applR,"appl(%s).",ruleName);
+7 is insufficient since you also need space for \0 char at the end of string. Making it +8 helped.
In SplitList,
char *curstr=(char*)malloc(leng);
there's a possibility of allocating zero bytes. leng + 1 helps.
After aforementioned changes, everything runs fine (if one could say so, since I'm not going to count memory leaks).
From the error message it actually looks like your if statement is not quite what you have posted here. It suggests that your if statement might be something like this:
if(s=0) {
}
Note the single = (assignment) instead of == (equality).
You cannot use free on pointers that were not created by malloc, calloc or realloc. From the Manpage:
free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

C Memory Overflow (v2)

EDIT: Updated code with new Pastebin link but it's still stopping at the info->citizens[x]->name while loop. Added realloc to loops and tidied up the code. Any more comments would be greatly appreciated
I'm having a few problems with memory allocation overflowing
http://pastebin.com/vukRGkq9 (v2)
No matter what I try, simply not enough memory is being allocated for info->citizens and gdb is often saying that it cannot access info->citizens[x]->name.
On occasion, I'll even get KERN_INVALID_ADDRESS errors directly after printf statements for strlen (Strlen is not used in the code at the point where gdb halts due to the error, but I'm assuming printf uses strlen in some way). I think it's something to do with how the structure is being allocated memory. So I was wondering if anyone could take a look?
You shouldn't do malloc(sizeof(PEOPLE*)), because it allocates exactly amount of bytes for pointer (4 bytes on 32bit arch).
Seems the thing you want to do is malloc(sizeof(PEOPLE) * N) where N is the max. number of PEOPLE you want to put into that memory chunk.
Clearly the problem lies with:
info->citizens = malloc(sizeof(PEOPLE *));
info->citizens[0] = malloc(sizeof(PEOPLE *));
info->citizens[1] = malloc(sizeof(PEOPLE *));
Think about it logically what you are trying to do here.
Your structs should almost certainly not contains members such as:
time_t *modtimes;
mode_t *modes;
bool *exists;
Instead you should simply use:
time_t modtimes;
mode_t modes;
bool exists;
In that way you do not need to dynamically allocate them, or subsequently release them. The reasons are that a) they're small and b) their size is known in advance. You would use:
char *name;
for a string field because it's not small and you don't know in advance how large it is.
Elsewhere in the code, you have the folllowing:
if(top)
{
PEOPLE *info;
info = malloc(sizeof(PEOPLE *));
}
If top is true then this code allocates a pointer and then immediately leaks it -- the scope of the second info is limited to the if statement so you can neither use it later nor can you release it later. You would need to do something like this:
PEOPLE *process(PEOPLE *info, ...)
{
if (top)
{
info = malloc(sizeof(PEOPLE));
}
info->name = strdup("Henry James");
info->exists = true;
return info;
}
It seems you have one too many levels of indirection. Why are you using **citizens instead of *?
Also, apart from the fact that you are allocating the space for a pointer, not the struct, there are a couple of weird things, such as the local variable info on line 31 means the initial allocation is out of scope once the block closes at line 34.
You need to think more clearly about what data is where.
Lots of memory allocation issues with this code. Those mentioned above plus numerous others, for example:
info->citizens[masterX]->name = malloc(sizeof(char)*strlen(dp->d_name)+1);
info->citizens[masterX]->name = dp->d_name;
You cannot copy strings in C through assignment (using =). You can write this as:
info->citizens[masterX]->name = malloc(strlen(dp->d_name)+1);
strcpy(info->citizens[masterX]->name, dp->d_name);
Or you could condense the whole allocate & copy as follows:
info->citizens[masterX]->name = strdup(dp->d_name);
Similarly at lines 143/147 (except in that case you have also allocated one byte too few in your malloc call).

How can dereferencing a NULL pointer in C not crash a program?

I need help of a real C guru to analyze a crash in my code. Not for fixing the crash; I can easily fix it, but before doing so I'd like to understand how this crash is even possible, as it seems totally impossible to me.
This crash only happens on a customer machine and I cannot reproduce it locally (so I cannot step through the code using a debugger), as I cannot obtain a copy of this user's database. My company also won't allow me to just change a few lines in the code and make a custom build for this customer (so I cannot add some printf lines and have him run the code again) and of course the customer has a build without debug symbols. In other words, my debbuging abilities are very limited. Nonetheless I could nail down the crash and get some debugging information. However when I look at that information and then at the code I cannot understand how the program flow could ever reach the line in question. The code should have crashed long before getting to that line. I'm totally lost here.
Let's start with the relevant code. It's very little code:
// ... code above skipped, not relevant ...
if (data == NULL) return -1;
information = parseData(data);
if (information == NULL) return -1;
/* Check if name has been correctly \0 terminated */
if (information->kind.name->data[information->kind.name->length] != '\0') {
freeParsedData(information);
return -1;
}
/* Copy the name */
realLength = information->kind.name->length + 1;
*result = malloc(realLength);
if (*result == NULL) {
freeParsedData(information);
return -1;
}
strlcpy(*result, (char *)information->kind.name->data, realLength);
// ... code below skipped, not relevant ...
That's already it. It crashes in strlcpy. I can tell you even how strlcpy is really called at runtime. strlcpy is actually called with the following paramaters:
strlcpy ( 0x341000, 0x0, 0x1 );
Knowing this it is rather obvious why strlcpy crashes. It tries to read one character from a NULL pointer and that will of course crash. And since the last parameter has a value of 1, the original length must have been 0. My code clearly has a bug here, it fails to check for the name data being NULL. I can fix this, no problem.
My question is:
How can this code ever get to the strlcpy in the first place?
Why does this code not crash at the if-statement?
I tried it locally on my machine:
int main (
int argc,
char ** argv
) {
char * nullString = malloc(10);
free(nullString);
nullString = NULL;
if (nullString[0] != '\0') {
printf("Not terminated\n");
exit(1);
}
printf("Can get past the if-clause\n");
char xxx[10];
strlcpy(xxx, nullString, 1);
return 0;
}
This code never gets passed the if statement. It crashes in the if statement and that is definitely expected.
So can anyone think of any reason why the first code can get passed that if-statement without crashing if name->data is really NULL? This is totally mysterious to me. It doesn't seem deterministic.
Important extra information:
The code between the two comments is really complete, nothing has been left out. Further the application is single threaded, so there is no other thread that could unexpectedly alter any memory in the background. The platform where this happens is a PPC CPU (a G4, in case that could play any role). And in case someone wonders about "kind.", this is because "information" contains a "union" named "kind" and name is a struct again (kind is a union, every possible union value is a different type of struct); but this all shouldn't really matter here.
I'm grateful for any idea here. I'm even more grateful if it's not just a theory, but if there is a way I can verify that this theory really holds true for the customer.
Solution
I accepted the right answer already, but just in case anyone finds this question on Google, here's what really happened:
The pointers were pointing to memory, that has already been freed. Freeing memory won't make it all zero or cause the process to give it back to the system at once. So even though the memory has been erroneously freed, it was containing the correct values. The pointer in question is not NULL at the time the "if check" is performed.
After that check I allocate some new memory, calling malloc. Not sure what exactly malloc does here, but every call to malloc or free can have far-reaching consequences to all dynamic memory of the virtual address space of a process. After the malloc call, the pointer is in fact NULL. Somehow malloc (or some system call malloc uses) zeros the already freed memory where the pointer itself is located (not the data it points to, the pointer itself is in dynamic memory). Zeroing that memory, the pointer now has a value of 0x0, which is equal to NULL on my system and when strlcpy is called, it will of course crash.
So the real bug causing this strange behavior was at a completely different location in my code. Never forget: Freed memory keeps it values, but it is beyond your control for how long. To check if your app has a memory bug of accessing already freed memory, just make sure the freed memory is always zeroed before it is freed. In OS X you can do this by setting an environment variable at runtime (no need to recompile anything). Of course this slows down the program quite a bit, but you will catch those bugs much earlier.
First, dereferencing a null pointer is undefined behavior. It can crash, not crash, or set your wallpaper to a picture of SpongeBob Squarepants.
That said, dereferencing a null pointer will usually result in a crash. So your problem is probably memory corruption-related, e.g. from writing past the end of one of your strings. This can cause a delayed-effect crash. I'm particularly suspicious because it's highly unlikely that malloc(1) will fail unless your program is butting up against the end of its available virtual memory, and you would probably notice if that were the case.
Edit: OP pointed out that it isn't result that is null but information->kind.name->data. Here's a potential issue then:
There is no check for whether information->kind.name->data is null. The only check on that is
if (information->kind.name->data[information->kind.name->length] != '\0') {
Let's assume that information->kind.name->data is null, but information->kind.name->length is, say, 100. Then this statement is equivalent to:
if (*(information->kind.name->data + 100) != '\0') {
Which does not dereference NULL but rather dereferences address 100. If this does not crash, and address 100 happens to contain 0, then this test will pass.
It is possible that the structure is located in memory that has been free()'d, or the heap is corrupted. In that case, malloc() could be modifying the memory, thinking that it is free.
You might try running your program under a memory checker. One memory checker that supports Mac OS X is valgrind, although it supports Mac OS X only on Intel, not on PowerPC.
The effect of dereferencing the null pointer is undefined by standard as far as I know.
According to C Standard 6.5.3.2/4:
If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.
So there could be crash or could be not.
You may be experiencing stack corruption. The line of code you are refering to may not be being executed at all.
My theory is that information->kind.name->length is a very large value so that information->kind.name->data[information->kind.name->length] is actually referring to a valid memory address.
The act of dereferencing a NULL pointer is undefined by the standard. It is not guaranteed to crash and often times won't unless you actually try and write to the memory.
As an FYI, when I see this line:
if (information->kind.name->data[information->kind.name->length] != '\0') {
I see up to three different pointer dereferences:
information
name
data (if it's a pointer and not a fixed array)
You check information for non-null, but not name and not data. What makes you so sure that they're correct?
I also echo other sentiments here about something else possibly damaging your heap earlier. If you're running on windows, consider using gflags to do things like page allocation, which can be used to detect if you or someone else is writing past the end of a buffer and stepping on your heap.
Saw that you're on a Mac - ignore the gflags comment - it might help someone else who reads this. If you're running on something earlier than OS X, there are a number of handy Macsbugs tools to stress the heap (like the heap scramble command, 'hs').
I'm interested in the char* cast in the call to strlcpy.
Could the type data* be different in size than the char* on your system? If char pointers are smaller you could get a subset of the data pointer which could be NULL.
Example:
int a = 0xffff0000;
short b = (short) a; //b could be 0 if lower bits are used
Edit: Spelling mistakes corrected.
Here's one specific way you can get past the 'data' pointer being NULL in
if (information->kind.name->data[information->kind.name->length] != '\0') {
Say information->kind.name->length is large. Atleast larger than
4096, on a particular platform with a particular compiler (Say, most *nixes with a stock gcc compiler) the code will result in a memory read of "address of kind.name->data + information->kind.name->length].
At a lower level, that read is "read memory at address (0 + 8653)" (or whatever the length was).
It's common on *nixes to mark the first page in the address space as "not accessible", meaning dereferencing a NULL pointer that reads memory address 0 to 4096 will result in a hardware trap being propagated to the application and crash it.
Reading past that first page, you might happen to poke into valid mapped memory, e.g. a shared library or something else that happened to be mapped there - and the memory access will not fail. And that's ok. Dereferencing a NULL pointer is undefined behavior, nothing requires it to fail.
Missing '{' after last if statement means that something in the "// ... code above skipped, not relevant ..." section is controlling access to that entire fragment of code. Out of all the code pasted only the strlcpy is executed. Solution: never use if statements without curly brackets to clarify control.
Consider this...
if(false)
{
if(something == stuff)
{
doStuff();
.. snip ..
if(monkey == blah)
some->garbage= nothing;
return -1;
}
}
crash();
Only "crash();" gets executed.
I would run your program under valgrind. You already know there's a problem with NULL pointers, so profile that code.
The advantage that valgrind beings here is that it checks every single pointer reference and checks to see if that memory location has been previously declared, and it will tell you the line number, structure, and anything else you care to know about memory.
As every one else mentioned, referencing the 0 memory location is a "que sera, sera" kinda thing.
My C tinged spidey sense is telling me that you should break out those structure walks on the
if (information->kind.name->data[information->kind.name->length] != '\0') {
line like
if (information == NULL) {
return -1;
}
if (information->kind == NULL) {
return -1;
}
and so on.
Wow, thats strange. One thing does look slightly suspicious to me, though it may not contribute:
What would happen if information and data were good pointers (non null), but information.kind.name was null. You don't dereference this pointer until the strlcpy line, so if it was null, it might not crash until then. Of course, earlier than t hat you do dereference data[1] to set it to \0, which should also crash, but due to whatever fluke, your program may just happen to have write access to 0x01 but not 0x00.
Also, I see you use information->name.length in one place but information->kind.name.length in another, not sure if thats a typo or if thats desired.
Despite the fact that dereferencing a null pointer leads to undefined behaviour and not necessarily to a crash, you should check the value of information->kind.name->data and not the contents of information->kind.name->data[1].
char * p = NULL;
p[i] is like
p += i;
which is a valid operation, even on a nullpointer. it then points at memory location 0x0000[...]i
You should always check whether information->kind.name->data is null anyway, but in this case
in
if (*result == NULL)
freeParsedData(information);
return -1;
}
you have missed a {
it should be
if (*result == NULL)
{
freeParsedData(information);
return -1;
}
This is a good reason for this coding style, instead of
if (*result == NULL) {
freeParsedData(information);
return -1;
}
where you might not spot the missing brace because you are used to the shape of the code block without the brace separating it from the if clause.
*result = malloc(realLength); // ???
Address of newly allocated memory segment is stored at the location referenced by the address contained in the variable "result".
Is this the intent? If so, the strlcpy may need modification.
As per my understanding, the special case of this problem is invalid access resulting with an attempt to read or write, using a Null pointer. Here the detection of the problem is very much hardware dependent. On some platforms, accessing memory for read or write using in NULL pointer will result in an exception.

Resources