realloc fails after multiple calls only when not debugging - c

The below code occasionally fails on the buffer = (char*) realloc(buffer, allocated * sizeof(char)); call (marked down below) that I use to dynamically allocate space for a char*,by allocating 1 char initially, and doubling the allocated amount every time the memory I already have is insufficient to store the string.
I have very similar code in many other parts of my project, with the same memory allocation policy and calls (changing only the type of the void* I pass to realloc).
I am using VS2010 to debug the problem, and when I start the program on debug mode, the function always completes successfully.
However, when calling the program from the command line, there is a good chance that one of the calls to realloc will fail after some time with an "Access violation reading location" error - though it doesn't happen all the time, and only happens after the function below has been called multiple times, with many reallocations having already taken place.
What's weirder, I put some prints before and after the realloc call to assert if the pointer location was changed, and, when I did so and ran the program, the calls to realloc stopped failing randomly.
What am I doing wrong?
TOKEN
next_token_file(FILE* file,
STATE_MACHINE* sm,
STATE_MACHINE* wsssm)
{
char* buffer = (char*) malloc(sizeof(char));
size_t allocated = 1;
size_t i = 0;
while(1)
{
/*
... code that increments i by one and messes with sm a bit. Does nothing to the buffer.
*/
// XXX: This fails when using realloc. Why?
if(i + 1 >= allocated)
{
allocated = allocated << 1;
buffer = (char*) realloc(buffer, allocated * sizeof(char));
}
buffer[i] = sm->current_state->state;
/*
... more code that doesn't concern the buffer
*/
}
// Null-terminate string.
buffer[++i] = 0;
TOKEN t = {ret, buffer};
return t;
}

Due to these lines
char* buffer = (char*) malloc(16 * sizeof(char));
size_t allocated = 1;
the program shrinks buffer for the first 4 re-allocations. So the program writes to unallocated memory from i=16 on, which is undefined behaviour, so anything could happen. Also this most likely smashes the memory management which in turn makes realloc() fail.
You might like to change those two lines to be:
size_t allocated = 16; /* or = 1 if the 16 was a typo. */
char * buffer = malloc(allocated);
Other notes:
sizeof(char) is always 1.
Do not cast the result of malloc/calloc/realloc as it is not necessary nor recommended: https://stackoverflow.com/a/605858/694576.
Do check the result of system calls.
Refering the last note, the following modifications should be applied
char * buffer = malloc(allocated);
might become:
char * buffer = malloc(allocated);
if (NULL == buffer)
{
/* Error handling goes here. */
}
and
buffer = (char*) realloc(buffer, allocated * sizeof(char));
might become:
{
char * pctmp = realloc(buffer, allocated);
if (NULL == pctmp)
{
/* Error handling goes here. */
}
else
{
buffer = pctmp;
}
}

More of a comment than an answer but I don't have 50 points to comment.
This:
char* buffer = (char*) malloc(16 * sizeof(char));
should be
char* buffer = (char*) malloc(1 * sizeof(char));
or
allocated = 16.

I dont know, when you are increasing or decreasing i.
But I would bet, acording to this snippet, your problem is: your reallocating infinitly, and as your not checking for realloc is returning NULL, that will crash your programm ;)
As allready said, even the not well running pritf's are conforming it, your violating your memory block. this will happen by reallocing the memory adress which has been overwritten outside the range.(excepting its UB anyway)
Or if you try to work if an invalid return value (what is when NULL is returned, what could happen because u aren't checking it)
Or if you request zerosized area(size parameter is 0) and you get returned an non zero pointer and you work with that one.
But 2nd case probably wont happen in your programm ;)

Related

C - fgets returns corrupt data

I am making a program that should read a file and do some stuff based on it, however I seem to have problem with reading the line properly.
I am using while loop with this function:
static int readLineFromFile(char **destination, int *allocSize, FILE *file)
{
char *newDest;
if (fgets(*destination, (*allocSize) - 2, file))
{
int strend = strlen(*destination);
while (*(*destination + strend - 1) != '\n')
{
printf("\"%s\"\n", *destination);
size_t length = (*allocSize) * 2; //WE ARE GOING TO ALLOCATE MORE MEMORY AND KEEP READING
newDest = realloc(*destination, length);
if (!newDest)
{
free(*destination);
return 2; //2 - FAILED ALLOC
}
*destination = newDest;
fgets(*destination + strend, (length / 2), file);
*allocSize = length;
strend = strlen(*destination);
}
*(*destination+strend-1) = '\0'; //WE DONT NEED THE \n AT THE END, SO WE JUST REPLACE IT WITH \0
printf("D %s\n", *destination);
return 0;
}
else{
if (feof(file)) { //IF NOTHING IS LEFT TO READ, WE CHECK IF IT IS BECAUSE OF EOF (1) OR AN ERROR (2)
return 1;
}
return 2;
}
}
where **destination is pointer to the pointer of mallocated area for the string, *allocSize pointer for the size of **destination and *file the file stream.
However, after 2nd reallocation (so, after I have had 2 lines longer than allocSize and had to realloc, doesn't matter after how many lines exactly), the printf-s (both after the realloc while cycle and at the beginning of the realloc cycle) return 5 chars correctly and 4 random ones after that ("ABCDE????" instead of "ABCDEFGHIJK..."). I thought that it was because of strtok function later in the while cycle (after reading the line), but seems it's not.
Then I found out that later in the code, I allocate space for parsed substrings of the line I loaded - and if I remove this part of the code, everything works fine again (it doesnt even matter, how many bytes I allocate, I still keep getting corrupted strings). So at this point I even started thinking if I haven't broken the OS somehow.
So, it would be nice if someone could tell me, if there is a mistake in this function, or if I should look for it elsewhere. Thanks.
Also, here are the other codes from the while cycle:
STRTOK, fileLine is the *destination from readLine:
char *strtokStart = malloc (strlen (fileLine)+2);
strcpy (strtokStart, fileLine);
char *strtokSave = fileLine;
strcpy (newKey, strtok_r (fileLine, "=", &strtokSave));
strcpy (newValue, strtok_r (NULL, "\n", &strtokSave));
free (strtokStart);
MALLOCATING additional strings:
config->topKey->key = (const char *) malloc(strlen(newKey) + 1);
config->topKey->value = (const char *) malloc(strlen(newValue) + 1);
if (!(config->topKey->key && config->topKey->value))
{
printf("ALLOC FAIL\n");
statusVal = 1;
break;
}
There are two things wrong with readLineFromFile:
If the file does not end in \n, the while loop keeps allocating more memory until realloc fails. Check return code of second fgets do detect that situation!
Bad error handling for failed realloc: free(*destination) leaves caller with bad pointer. Best to just remove free. Or add *destination=NULL.
Otherwise readLineFromFile is fine and should work with valid input files. In the absence of invalid input files, there are probably more errors elsewhere in your code.
readLineFromFile should be called with a malloc'ed buffer, of course.

Program with realloc behave differently in Valgrind

I wrote a function to read a string with fgets that uses realloc() to make the buffer grow when needed:
char * read_string(char * message){
printf("%s", message);
size_t buffsize = MIN_BUFFER;
char *buffer = malloc(buffsize);
if (buffer == NULL) return NULL;
char *p;
for(p = buffer ; (*p = getchar()) != '\n' && *p != EOF ; ++p)
if (p - buffer == buffsize - 1) {
buffer = realloc(buffer, buffsize *= 2) ;
if (buffer == NULL) return NULL;
}
*p = 0;
p = malloc(p - buffer + 1);
if (p == NULL) return NULL;
strcpy(p, buffer);
free(buffer);
return p;
}
I compiled the program and tried it, and it worked like expected. But when I run it with valgrind, the function returns NULL when the read string is >= MIN_BUFFER and valgrind says:
(...)
==18076== Invalid write of size 1
==18076== at 0x8048895: read_string (programme.c:73)
==18076== by 0x804898E: main (programme.c:96)
==18076== Address 0x41fc02f is 0 bytes after a block of size 7 free'd
==18076== at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18076== by 0x8048860: read_string (programme.c:76)
(...)
==18076== Warning: silly arg (-48) to malloc()
(...)
I added a printf statement between *p=0; and p=malloc... and it confirmed that the arg passed had a value of -48.
I didn't know that programs don't run the same way when launched alone and with valgrind. Is there something wrong in my code or is it just a valgrind bug?
When you realloc the buffer, your pointer 'p' still points at the old buffer.
That will stomp memory, and also cause future allocations to use bogus values.
realloc returns a pointer to a new buffer of the requested size with the same contents as the pointer passed in, assuming that the pointer passed in was previously returned by malloc or realloc. It does not guarantee that it's the same pointer. Valgrind very likely modifies the behavior of realloc, but keeps it within the specification.
Since you are resizing memory in a loop, you would be better served by tracking your position in buffer as an offset from the beginning of buffer rather than a pointer.
As man 3 realloc says
...The function may move the memory block to a new location.
What this means, is that
p = malloc(p - buffer + 1);
is the problem. If realloc() was called, buffer might be pointing to a new block of memory and expression
(p - buffer)
does not make any sense.

Segment fault in realloc() on loop

I'm trying reallocate more 256 bytes to buffer on each loop call. In this buffer, I will store the buffer obtained from read().
Here is my code:
#define MAX_BUFFER_SIZE 256
//....
int sockfd = socket( ... );
char *buffer;
buffer = malloc( MAX_BUFFER_SIZE );
assert(NULL != buffer);
char *tbuf = malloc(MAX_BUFFER_SIZE);
char *p = buffer;
int size = MAX_BUFFER_SIZE;
while( read(sockfd, tbuf, MAX_BUFFER_SIZE) > 0 ) {
while(*tbuf) *p++ = *tbuf++;
size = size + MAX_BUFFER_SIZE; // it is the right size for it?
buffer = realloc(buffer, size);
assert(NULL != buffer);
}
printf("%s", buffer);
free(tbuf);
free(p);
free(buffer);
close(sockfd);
But the above code returns segment fault. Where am I wrong?
These are the problems that are apparent to me:
Your realloc can modify the location to which buffer points. But you fail to modify p accordingly and it is left pointing into the previous buffer. That's clearly an error.
I see potential for another error in that the while loop need not terminate and could run off the end of the buffer. This is the most likely cause of your segmentation fault.
The way you use realloc is wrong. If the call to realloc fails then you can no longer free the original buffer. You should assign the return value of realloc to a temporary variable and check for errors before overwriting the buffer variable.
You should not call free on the pointer p. Since that is meant to point into the block owned by buffer, you call free on buffer alone.
Thing is read doesn't add a 0-terminator. So your inner while is undoubtedly stepping outside the allocated memory:
while(*tbuf) *p++ = *tbuf++;
Another problem is that you are freeing stuff you didn't receive via malloc. By the time you call free, you will have incremented both p and tbuff which you try to free.
The whole buffer allocation things looks useless as you're not actually using it anywhere.
When you use realloc on buffer, it is possible that the address of buffer is changed as a result of changing the size. Once that happens, p is no longer holding the correct address.
Also towards the end, you are freeing both p and buffer while they point to the same location. You should only free one of them.

Reading line from file causes crash

I'm trying to read a line from a file character by character and place the characters in a string; here' my code:
char *str = "";
size_t len = 1; /* I also count the terminating character */
char temp;
while ((temp = getc(file)) != EOF)
{
str = realloc(str, ++len * sizeof(char));
str[len-2] = temp;
str[len-1] = '\0';
}
The program crashes on the realloc line. If I move that line outside of the loop or comment it out, it doesn't crash. If I'm just reading the characters and then sending them to stdout, it all works fine (ie. the file is opened correctly). Where's the problem?
You can't realloc a pointer that wasn't generated with malloc in the first place.
You also have an off-by-one error that will give you some trouble.
Change your code to:
char *str = NULL; // realloc can be called with NULL
size_t len = 1; /* I also count the terminating character */
char temp;
while ((temp = getc(file)) != EOF)
{
str = (char *)realloc(str, ++len * sizeof(char));
str[len-2] = temp;
str[len-1] = '\0';
}
Your issue is because you were calling realloc with a pointer to memory that was not allocated with either malloc or realloc which is not allowed.
From the realloc manpage:
realloc() changes the size of the memory block pointed to by ptr to size bytes.
The contents will be unchanged to the minimum of the old and new
sizes; newly allocated memory will be uninitialized. If ptr is NULL,
then the call is equivalent to malloc(size), for all values of size;
if size is equal to zero, and ptr is not NULL, then the call is
equivalent to free(ptr). Unless ptr is NULL, it must have been
returned by an earlier call to malloc(), calloc() or realloc(). If
the area pointed to was moved, a free(ptr) is done.
On a side note, you should really not grow the buffer one character at a time, but keep two counter, one for the buffer capacity, and one for the number of character used and only increase the buffer when it is full. Otherwise, your algorithm will have really poor performance.
You can't realloc a string literal. Also, reallocing every new char isn't a very efficient way of doing this. Look into getline, a gnu extension.

What's wrong with strcpy()? (Segmentation fault) [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 3 years ago.
What is wrong with strcpy() in this code?
void process_filedata(char *filename)
{
void* content;
const char * buffer;
char * temp;
char * row;
char * col;
int lsize,buflen,tmp,num_scan; //num_scan - number of characters scanned
int m=0,p=0,d=0,j=0; //m - machine, p - phase, d- delimiter, j - job
FILE *file_pointer = fopen("machinetimesnew.csv","r");
if(file_pointer == NULL)
{
error_flag = print_error("Error opening file");
if(error_flag) exit(1);
}
fseek(file_pointer, 0 ,SEEK_END);
lsize = ftell(file_pointer);
buflen = lsize;
rewind(file_pointer);
// content = (char*) malloc(sizeof(char)*lsize);
fread(content,1,lsize,file_pointer);
buffer = (const char*) content;
strcpy(temp,buffer);
row = strtok(temp,"\n");
...............
...............
I am getting a segmentation fault..
You're not allocating any space for temp. It's a wild pointer.
There are actually three segmentation faults here:
fread(content,1,lsize,file_pointer);
strcpy(temp,buffer);
row = strtok(temp,"\n");
The first one is fread() which is attempting to write to memory that does not yet exist as far as your process is concerned.
The second one is strcpy(), (expounding on the first) you are attempting to copy to a pointer that points to nothing. No memory (other than the pointer reference itself) has been allocated for temp, statically or dynamically.
Fix this via changing temp to look like this (allocating it statically):
char temp[1024];
Or use malloc() to dynamically allocate memory for it (as well as your other pointers, so they actually point to something), likewise for content. If you know the needed buffer size at compile time, use static allocation. If not, use malloc(). 'Knowing' is the subject of another question.
The third one is strtok() , which is going to modify temp en situ (in place), which it obviously can not do, since temp was never allocated. In any event, don't expect temp to be the same once strtok() is done with it. By the name of the variable, I assume you know that.
Also, Initializing a pointer is not the same thing as allocating memory for it:
char *temp = NULL; // temp is initialized
char *temp = (char *) malloc(size); // temp is allocated if malloc returns agreeably, cast return to not break c++
Finally, please get in the habit of using strncpy() over strcpy(), its much safer.
Nothing's wrong with strcpy. You haven't initialised temp.
There's yet another mistake. fread does not add a nul character to the end of the buffer. That's because it only deals with arrays of bytes, not nul-terminated strings. So you need to do something like this:
content = malloc(lsize + 1);
fread(content,1,lsize,file_pointer);
content[lsize] = 0;
temp = malloc(lsize + 1);
strcpy(temp, content);
or this:
content = malloc(lsize);
fread(content,1,lsize,file_pointer);
temp = malloc(lsize + 1);
memcpy(temp, content, lsize);
temp[lsize] = 0;
(Also, in real code you should check the results of fread and malloc.)
you didn't allocate memory for temp
char * temp hasn't been initialized and you consequently haven't allocated any memory for it.
try:
temp = (char *)malloc(SIZE);
where SIZE is however much memory you want to allocate for temp
This piece of code intrigues me:
if(file_pointer == NULL)
{
error_flag = print_error("Error opening file");
if(error_flag) exit(1);
}
Shouldn't you exit unconditionally if the file_pointer is NULL?

Resources