realloc and free causes "double free or corruption" - c

Bear with me. I have not coded in c in 8 years and am totally baffled why my string manipulation is not working. I am writing a program that loops forever. In the loop I initialize two char pointers each is passed to a function that add text to the char pointer (array). When the functions are done I print the char pointer and free the two char pointers. However the program dies after 7 iterations with the following error message
* glibc detected * ./test: double free or corruption (fasttop): 0x0804a168 ***
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include string.h
#include stdio.h
#include stdlib.h
#include errno.h
#include time.h
char *SEPERATOR = "|";
void getEvent (char* results);
void getTimeStamp(char* timeStamp, int timeStampSize);
void stringAppend(char* str1, char* str2);
int main (int argc, char *argv[])
{
int i = 0;
while(1)
{
i++;
printf("%i", i);
char* events= realloc(NULL, 1);
events[0] = '\0';
getEvent(events);
char* timestamp= realloc(NULL, 20);
timestamp[0] = '\0';
getTimeStamp(timestamp, 20);
printf("%s", events);
printf("timestamp: %s\n", timestamp);
free(events);
free(timestamp);
}
}
void getEvent (char* results)
{
stringAppend(results, "a111111111111");
stringAppend(results, "b2222222222222");
}
void getTimeStamp(char* timeStamp, int timeStampSize)
{
struct tm *ptr;
time_t lt;
lt = time(NULL);
ptr = localtime(&lt);
int r = strftime(timeStamp, timeStampSize, "%Y-%m-%d %H:%M:%S", ptr);
}
void stringAppend(char* str1, char* str2)
{
int arrayLength = strlen(str1) + strlen(str2) + strlen(SEPERATOR) + 1;
printf("--%i--",arrayLength);
str1 = realloc(str1, arrayLength);
if (str1 != NULL)
{
strcat(str1, SEPERATOR);
strcat(str1, str2);
}
else
{
printf("UNABLE TO ALLOCATE MEMORY\n");
}
}

You are reallocating str1 but not passing the value out of your function, so the potentially changed pointer is leaked, and the old value, which has been freed by realloc, is freed again by you. This causes the "double free" warning.

The problem is that while stringAppend reallocates the pointers, only stringAppend is aware of this fact. You need to modify stringAppend to take pointer-to-pointers (char **) so that the original pointers are updated.

This line in stringAppend:
str1 = realloc(str1, arrayLength);
changes the value of a local variable in stringAppend. This local variable named str1 now points to either the reallocated memory or NULL.
Meanwhile local variables in getEvent keep the values they had before, which now usually point to freed memory.

All the comments where very helpfull. Of course it makes total sense why the error was happening. I ended up solving it by making the following changes.
For both the getEvent and stringAppend I return the char pointer.
e.g.
char* stringAppend(char* str1, char* str2)
{
int arrayLength = strlen(str1) + strlen(str2) + strlen(SEPERATOR) + 1;
printf("--%i--",arrayLength);
str1 = realloc(str1, arrayLength);
if (str1 != NULL)
{
strcat(str1, SEPERATOR);
strcat(str1, str2);
}
else
{
printf("UNABLE TO ALLOCATE MEMORY\n");
}
return str1;
}

This isn't an answer to your question (and you don't need one, since the error has been pointed out), but I do have some other comments about your code:
char* events= realloc(NULL, 1);
events[0] = '\0';
You don't test that realloc successfully allocated memory.
char* timestamp= realloc(NULL, 20);
timestamp[0] = '\0';
Same problem here. In this case, you don't need realloc at all. Since this is a fixed-size buffer, you could use just:
char timestamp[20] = "";
And don't do this:
str1 = realloc(str1, arrayLength);
because if realloc fails, you'll orphan the memory that str1 was pointing to before. Instead:
char* temp = realloc(str1, arrayLength);
if (temp != NULL)
{
str1 = temp;
...
}
Note that since you're modifying stringAppend to return the new string, you should do similar checks in the calling functions.
Also, "separator" is spelled with two As, not with two Es.

Related

function returns address of local variable [-Wreturn-local-addr] sprintf

i ma new c and i am trying sprintf along with pointers. all i get in console is return buf; as is please help me with this code.
#include <stdio.h>
char* stringa(char* str);
int main()
{
char* ss = "123";
stringa(ss);
return 0;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
i tried many other ways too like sprintf_c and my computer shut down for serious. i am learning c.
Maybe this is what you want
#include <stdio.h>
char* stringa(char* dest, char* src)
int main()
{
char buf [100] ;
char* ss = "123";
printf("%s\n", stringa(buf, ss));
return 0;
}
char* stringa(char* dest, char* src)
{
sprintf(dest,"hello %s", src);
return dest;
}
In function 'char* stringa(char* str)' you are not allocating space in the heep for the char array 'buf' you are allocating space on the stack for that variable. (meaning after the function finishes, the variable 'buf' will be wiped away because it will be out of scope) therefore you must ask the compiler to allocate space in memory for this array, I recommend using malloc()
ex:
char* stringa( char* str)
{
char *buf = (char*)malloc(sizeof(char) * 100);
sprintf(buf,"hello %s", str);
return buf;
}
char* stringa( char* str)
{
char buf [100] ;
sprintf(buf,"hello %s", str);
return buf;
}
The problem with this code is that the buf char array is local to the stringa function. When the function returns, the memory occupied by the buf array is not valid anymore (for example, it could be reused later to store the content of other variables, arrays, etc.).
So when the function returns, you are giving the caller a pointer to garbage memory, to invalid data. The C compiler is trying to help you with that warning message; it's telling you: "Sorry, you are trying to pass back to the caller the address of a local variable (i.e. the buf char array) that is not valid anymore when the function terminates."
To fix this problem one option could be to allocate the char array for the output string at the call site, and let the invoked stringa function write into the caller-provided array:
#include <stdio.h>
char* stringa(char* dest, const char* str);
int main()
{
const char* ss = "123";
char buf[100];
stringa(buf, ss);
return 0;
}
/* Write the final message into 'dest'.
* Return the same dest address.
*/
char* stringa(char* dest, const char* str)
{
/* Note: better using a safe string function
* to prevent buffer overflows (e.g. sprintf_s),
* passing the maximum destination array size as well.
*/
sprintf(dest,"hello %s", str);
return dest;
}
Note that I also added some consts in your code to enforce some const-correctness for read-only input strings.

Segmentation fault when trying to copy string with double pointer

Jus started learning about pointers and im stuck with this program outputting a segmentation fault.
Its supposed to copy the first 10 Characters of a string to the location pointed by the double pointer
using gdb ive found that **pt=*s; produces the seg fault
#include <stdio.h>
#include <stdlib.h>
void str1(char *s, char **pt);
void str1(char *s, char **pt){
for(int i=0;i<10;i++){
**pt=*s;
pt++;
s++;
}
}
int main (void) {
char str[30] = "223This is test";
char *ptr;
str1(str, &ptr);
printf("%s", ptr);
return 0;
}
First of all ptr is not initialized, you can't really use it until you reserve space for it or store a valid memory address in it, i.e. make it point to some valid variable.
char *ptr = malloc(11);
Then you need to increment it properly in the function:
(*pt)++;
Once the copy is completed you need to null terminate the char array so it can be treatead as a string, aka a null terminated char array.
**pt = '\0';
Now as ptr was passed as a pointer to pointer, the increment is known by the caller, main in this case, so when you try to print it, it prints nothing because it's pointing to the end of the char array, we need to bring it back to the beggining.
*pt -= 10;
Corrected code with comments taking yours as base:
Live demo
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
void str1(char *s, char **pt) {
for (int i = 0; i < SIZE; i++) {
**pt = *s;
(*pt)++; //properly increment pt
s++;
}
**pt = '\0'; //null terminate copied string
//since ptr was passed as **, the increment is known by the caller
//now ptr will be pointing to the end of the string
//we have to bring it back to the beginning
*pt -= SIZE;
}
int main(void) {
char str[] = "223This is test";
char *ptr = malloc(SIZE + 1); //space for 10 character + null-terminator
//check for allocation errors
if(ptr == NULL){
perror("malloc");
return EXIT_FAILURE;
}
str1(str, &ptr);
printf("%s", ptr);
free(ptr);
return EXIT_SUCCESS;
}
You probably want this:
#include <stdio.h>
#include <stdlib.h>
void str1(char* s, char** pt) {
char *p = malloc(100); // allocate memory for destination
*pt = p; // store it for the caller
for (int i = 0; i < 10; i++) {
*p = *s;
p++;
s++;
}
*p = 0; // put string terminator, otherwise printf won't work correctly
}
int main(void) {
char str[30] = "223This is test";
char *ptr; // for now p points nowhere
str1(str, &ptr); // now p points to the memory allocated in str1
printf("%s", ptr);
free(ptr); // free memory for completeness
return 0;
}

Memory management in replace function

I'm trying to make a replace function in C. I know there are many out there that I could copy, but I decided to make my own function in order to practice.
However, I'm stuck at this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void replace_content(char *rep, char *with, char **text) {
int len_rep = strlen(rep);
int len_with = strlen(with);
char *p = *text;
int new_text_size = 0;
char *new_text = malloc(new_text_size);
do {
if (!strncmp(p, rep, len_rep)) {
new_text_size += len_with;
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
p += len_rep;
} else {
new_text_size++;
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
p++;
}
} while (*p != '\0');
*text = malloc(new_text_size);
strcpy(*text, new_text);
}
int main() {
printf("Testing a replace function:\n");
char *text =
"<serviceName>\n"
" <label1>a</label1>\n"
" <label2>b</label2>\n"
" <label3>c</label3>\n"
"</serviceName>\n";
printf("Before replace:\n%s", text);
replace_content("serviceName>", "serviceNameResponse>", &text);
printf("After replace:\n%s", text);
return 0;
}
This is the output I'm seeing so far:
Testing a replace function:
Before replace:
<serviceName>
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceName>
After replace:
<0�serviceNameRespons
<label1>a</label1>
<label2>b</label2>
<label3>c</label3>
</serviceNameResponse>
My guess is that I'm doing something wrong with dynamic memory, but the more I look into my code the more confused I am.
These two statements are problematic:
new_text = (char *) realloc(new_text, new_text_size + 1);
strcat(new_text, with);
The first problem is that you should never assign back directly to the pointer you reallocate. That is because realloc may fail and return NULL, making you lose the original pointer.
The second problem is that new_text doesn't initially point to a null-terminated string, which makes the call to strcat undefined behavior.
There is also a problem in the else branch:
new_text = (char *) realloc(new_text, new_text_size);
new_text[new_text_size-1] = *p;
Besides the same problem with reassigning back to the pointer being reallocated, you don't terminate the string in new_text.
May the reason is malloc(0) in line 10 char *new_text = malloc(new_text_size);.
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that
can later be successfully passed to free().
I suggest using char *new_text = NULL; instead.

Is this a correct method using free() in C?

If I have this function foo() and I'm calling it from another function foo2(); must I free the memory in the calling function like this?
char *foo(char *str1){
char *str2;
str2 = malloc((sizeof(char) * strlen(str1)) + 1);
memcpy(str2, str1, strlen(str1) + 1)
return str2;
}
void foo2(void){
char *str1 = "Hello world!"
char *str2;
str2 = foo(str1);
...some stuff
free(str2); //Should I do this here?
}
Yes, except you don't test that your malloc is successful
You can free the allocated memory anywhere given the fact that you did the allocation, that the allocation was successful, and that the memory was not already freed.
Yeah that would work, however you have a bug:
char *foo(const char *str1)
{
char *str2 = (char *)malloc((sizeof(char) * strlen(str1)) + 1);
if (str2 != NULL)
memcpy(str2, str1, strlen(str1) + 1);
return str2;
}
void foo2
{
char *str1 = "Hello world!"
char *str2;
str2 = foo(str1);
...some stuff
free(str2);
}
Conventionally you would document the fact that the caller is responsible for freeing the returned pointer using free().
Also your foo() function is nothing more than strdup().
Yes, it is right. foo() allocates some memory and it must be freed by the caller. It's not a very good design but it works. It could be better if foo() accepts two parameters: output buffer and its size.
void foo(char* input, char* output, int* bufferSize);
If output is NULL the required size is written in bufferSize by foo().
Yes. The memory needs to be freed at some point. As you can see, you now have a tight coupling between the foo function and any of its callers. One common alternative is to pass in a pointer to a char array and the size of it. The function then returns whether it filled out the array properly. This moves the responsibility of both allocating and freeing to the caller.
bool * foo(char * str, size_t size)
{
if(size < FOO_REQUIRED_SIZE) {
return FALSE;
} else {
...
return TRUE;
}
}
void foo2(void)
{
char str[FOO_REQUIRED_SIZE];
foo(str, ARRAY_SIZE(str));
}
Instead of simply returning FALSE if the function failed, you can furthermore document the required size of the array. Or alternatively provide a function which calculates the required size and returns it.
size_t getRequiredBufSizeForFoo()
{
// Calculate how many bytes required
return ...;
}
void foo2(void)
{
size_t len = getRequiredBufSizeForFoo();
char str[len];
foo(str, len);
}

How to set pointer reference through a function

In C, I am trying to set a pointer's value by sending it to a function, but the value wont change outside of the function. Here is my code:
#include <stdio.h>
void foo(char* str) {
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
str = new_str;
}
int main (int argc, char *argv[]) {
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(str);
printf("str = %s\n", str);
}
I want to print out:
str = new test
but this code prints out:
str = test
Any help will be appreciated. Thanks in advance.
There is no pass-by-reference in C. If you provide str as the argument to a function in C, you are always passing the current value of str, never str itself.
You could pass a pointer to str into the function:
void foo(char** pstr) {
// ...
*pstr = new_str;
}
int main() {
// ...
foo(&str);
}
As Eiko says, your example code leaks the first memory allocation. You're no longer using it, and you no longer have a pointer to it, so you can't free it. This is bad.
You need to use pointer to the pointer, untested:
#include <stdio.h>
void foo(char** str)
{
char* new_str = malloc(100);
memset(new_str, 0, 100);
strcpy(new_str, (char*)"new test");
if (str) { /* if pointer to pointer is valid then */
if (*str) /* if there is a previous string, free it */
free(*str);
*str = new_str; /* return the string */
}
}
int main (int argc, char *argv[])
{
char* str = malloc(100);
memset(str, 0, 100);
strcpy(str, (char*)"test");
foo(&str);
printf("str = %s\n", str);
}
You are just reassigning a pointer, which is a local variable in foo.
If you want to copy the string, use strcpy(str, new_str);
You could pass a reference to the pointer instead and reassign, but this can easily lead to memory leaks and is hard to maintain.
Edit: For the pseudo pass by reference see the answer by Steve.
I did it this way by returning the pointer from the function. There is no reason to use malloc in this case, so you don't have to worry about freeing.
gcc 4.4.3 c89
char* print_test(char *str)
{
char *new_str = "new_test";
printf("new_str [ %s ]\n", new_str);
str = new_str;
return str;
}
int main(void)
{
char *str = "test";
printf("str [ %s ]\n", str);
str = print_test(str);
printf("str [ %s ]\n", str);
return 0;
}

Resources