Freeing malloc will not erase char data - c

I made a smaller scenario of my bigger problem. What I try to do is pass a string to a function which will make a new string out of it. However I ran into some problems.
I have defined string as
typedef char string[1024];
Then I have a function that takes a string and makes a new string which get filled with the old string and a dot char
string* add_sth_to_string(char* msg){
string* newStr=malloc(sizeof(string)); // malloc a newStr
strcpy(*newStr, msg); // copying msg to newStr
char buff[1024]; // making a buffer
strcat(buff, "."); // adding a dot to buffer
strcat(buff, *newStr); // adding msg to buffer
strcpy(*newStr, buff); // copying buffer to newStr
return newStr;
}
Then in main I try to use this function 3 times for a new string each time:
for (i=0; i<3; i++){
string* newStr;
newStr=add_sth_to_string("test");
printf("str: %s\n", *newStr);
free(newStr);
// can even printf here
}
This is the weird output I get:
str: .test
str: .test.test
str: .test.test.test
When I would expect to get:
str: .test
str: .test
str: .test
Anyone who can point out what is happening? Something else I find weird is that I can printf the value of newStr just after I have freed it.

You are using buff without initializing it. Try:
char buff[1024];
buff[0] = 0;
Something else I find weird is that I can printf the value of newStr
just after I have freed it.
Accessing memory after freeing it is undefined behavior. Typically, for performance reasons, free doesn't zero the memory.
That's 2 cases of undefined behavior in the same question + one really weird typedef. Keep it up!

Try changing
strcat(buff, ".");
into
strcpy(buff, ".");
Or alternativly initialise buff when declaring it like so:
char buff[1024] = "";

You should clear content of buf[1024] each iteration.
UPDATE
Because buf[1024] will not be zero-ed automatically when allocated on the stack. And you choose strcat to concatenate two string, which will find a \0-terminate. Thus if buf contains some default value, it will introduce obfuscated output.
Use buf[1024] = ""; to allocate a buffer will correct the output.

string* newStr=malloc(sizeof(string)); // malloc a newStr
strcpy(*newStr, msg); // copying msg to newStr
This will also crash. string is a pointer so sizeof of it will return 4 or 8, not what you wanted to do.
Ok, forget about my remark you made a typedef, but I let it here to show you why the typedef is a bad idea. At first glance it obfuscated the fact that it was an array and not a pointer, on a 30 line program it's not a probleme, but when you have to maintain a 200 000 lines project (as I do), you will start to hate these kind of things.
Another point, you should avoid to work with fixed sized strings of 1024 bytes. 1024 is not that big (even homecomputer of the 80s had screens bigger than that) and for the majority if strings, which are fairly short, you spoil a lot of memory for nothing.

Related

Error :"pointer being realloc'd was not allocated" on macOS but works on Windows when trying to realloc twice

I'm trying to implement a function that concatenate two strings, but I keep getting the same error.
"pointer being realloc'd was not allocated"
When I compiled the same code on a windows machine it worked, is it something that I'm missing?
The code below is basically what I'm trying to do.
main:
int main() {
int length = 4096;
char *string = malloc(length * sizeof(char));
createString(string, length);
realloc(string, 30);
return 0;
}
createString:
void createString(char * string, int length) {
char *copyAdress = string;
char *temp ="";
int counter2 = 0;
fflush(stdin);
fgets(string, length,stdin);
while(*string != EOF && *string != *temp ) {
string++;
counter++;
}
string = copyAdress;
realloc(string, (counter)*sizeof(char));
}
Thanks!
Edit:
I want createString to change the size of string to the length of the string that I get with fgets, while having the same address as the string that I sent in, so I can allocate more memory to it later when I want to add another string to it.
There are several issues:
realloc(string, (counter)*sizeof(char)); is wrong, you need string = realloc(string, (counter)*sizeof(char)); because realloc may return a different address.
Calling createString(string, length); won't modify string
If you want a more accurate answer you need to tell us what exactly createString is supposed to do. In your code there is no attempt to concatenate two strings.
Let's work through this in order of execution.
fflush(stdin); is undefined behaviour. If you really need to clear everything in the stdin you have to find another way (a loop for example). There are compilers/systems with a defined implementation but I would not count on it.
string++; is superflous as you overwrite string after the loop.
realloc(string, (counter)*sizeof(char));
should be
char *temp = realloc(string, (counter)*sizeof(char));
if (temp != NULL)
string = temp;
This way you get the pointer where your new string is located, but I suggest you read the refecerence for realloc. In essence you do not know if it has been moved and the old address might be invalid from that point on. So dereferencing it is also undefined behaviour.
After this you would have to return the new address of string or pass the address of the pointer to your function.
The same problem repeats with the second realloc. You only got to know your first call was wrong, because the second call noticed that you do not have valid data in what you thought would be your string.
In regards to your comment: It is not possible to use realloc and to be sure that the reallocated memory is in the same place as before.
If you realloc some memory, the pointer pointing to the original memory becomes invalid (unless realloc failed and returned NULL). So calling realloc twice on the same pointer should indeed not work (if it didn't return NULL the first time).
See the answers from others about what you do wrong. However, the eror message means that on MacOS, the realloc in createString deallocated the orignal string and allocated a new one, and now your realloc in main tries to realloc a pointer that is no longer valid (allocated). On Windows, the memory was not deallocated in createString and so the second call of realloc (in main) is given a valid pointer.

try use sprintf in an string with a previously unknown size generate a free() invalid next size

I need to use sprintf in an string with a previously unknown size.
This works, but generates a warning/error in the console.
What is wrong here?
// request a dummy size
char* str = (char *)malloc(2);
// first pass, just to get the final size
int size = sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// realloc to correct size
str = (char *)realloc(str,sizeof(char)*size);
// second pass , get the full string
sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// free after use
free(str);
This generate 2 errors:
Error in "foo" realloc(): invalid next size: 0x00007f6dc8009b70 ***
Error in "foo" free(): invalid next size (fast): 0x00007f6dc8009b70 ***
There are actually two problems in your code. First of all, your fist call to sprintf writes to a memory region too small. Doing that invokes undefined behavior which means that anything can start misbehaving and it does. The second one is that after realloc call the memory region is still not large enough - there is no place for ending \0 character.
In order to fix that, use snprint, which is almost like sprintf but it takes one additional argument - size of allocated memory. It never writes more than this amount of characters to the buffer. It still, however, returns the number of characters that would be written if the buffer was large enough. Now, you can use realloc to resize the buffer to one more byte than the returned value.
Note that if you happen to use gcc and you don't care for portable code, you may use asprintf instead.
You can use snprintf() to find out how much space you need.
In Visual Studio there is _snprintf():
char* str;
// get the size
int size = _snprintf(NULL,0,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// allocate memory
str = (char *)malloc(size+1);
// get the string
sprintf(str,"init_display(%d,%d,%d,%d,%s)",width,height,glwidth,glheight,title);
// free after use
free(str);
sprintf(str,"init_display(%d,... over writes the 2 char allocation of str.
If one does not want to sprintf() twice, consider a buffer that is certainly over-sized, then realloc().
static const char format[] = "init_display(%d,%d,%d,%d,%s)";
size_t siz = sizeof(format) + 4*(sizeof(int)*CHAR_BIT/3 + 3) + strlen(title) + 1;
char *str = malloc(siz);
assert(str != NULL);
siz = sprintf(str, format, width, height, glwidth, glheight, title) + 1;
char *str2 = realloc(str, siz);
assert(str2);
str = str2;
// free after use
free(str);
#Krzysztof Adamski answer is less error prone as with this approach, code needs to absolutely correctly calculate the maximum buffer size.

add in a char* some other data c code

I have this part in a code:
char* data="My name is: ";
I would like to add to this the argv[1] argument with represents a name. How to do this in c code? I've tried strcpy and strcat but i have segmentation fault when Ipcp do this:
strcpy(data,argv[1]);
Can anyone please help?
Also why this: data=data+argv[1] is not working?
You need to provide some memory, where the result of the concatentation can be stored into. For example:
char buffer[1024];
strcpy(buffer, "My name is: ");
strcat(buffer, argv[1]);
Note, however, that this is error prone: if the value of argv[1] combined with the prefix string is longer than 1024 characters, this produces a buffer overflow. So, maybe something like this:
char* prefix = "My name is: ";
int length = strlen(prefix) + strlen(argv[1]) + 1;
char* buffer = malloc(length);
if (!buffer) abort();
else
{
strcpy(buffer, prefix);
strcat(buffer, argv[1]);
/* Do something with buffer here. And don't
* forget to free it, once you no longer need
* it. This is C -- no garbage collection. */
free(buffer);
}
Also why this: data=data+argv[1] is not working?
About this one - in C data and argv are nothing more than pointers to address in the memory containing your string. You can't concatenate strings(char*) this way.
I suggest to take a look at the string library and maybe a bit more in C as a whole.
Memory for data will be allocated in read-only section. so modifying will cause issue.
where in memory are string literals ? stack / heap?
+ operator will not do concat as you thought.
strcat() function is implemented in string.h.
You cant append to th data pointer because there are no space in it
char result_data [1024];
char* data="My name is: ";
strcat(result_data, data);
strcat(result_data, argv[1]);

Sprintf Segmentation Fault

numCheck is number between 1-1000. This code gives me a segfault only when I collect the results of sprintf in charcheck. If I simply use sprintf without using the results, I don't get a seg fault. What's happening here?
char * numString;
int charcheck = sprintf(numString, "%d", numCheck);
You need to provide your own memory for sprintf. Also, don't use sprintf, but rather snprintf:
char buf[1000] = {0};
snprintf(buf, 999, ....);
Alternatively you can allocate memory dynamically:
char * buf = new char[BUFSIZE];
snprintf(buf, BUFSIZE-1, ...);
/* ... */
delete[] buf;
The pointer given as the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string.
In this case you didn't initialize numString to point to some memory you allocated for the formatted string. Since numString isn't initialized it might point anywhere, and in your case trying to write the formatted output to that location results in a segmentation fault.
The first argument to sprintf must point to a valid buffer. You have a char* but it points to garbage.
Change your code to:
char numString[80] = { };
int charcheck = sprintf(numString, "%d", numCheck);
So that numString actually points to a valid buffer (of 80 characters in this example, all elements of which are initialised to 0).
It would also be good to use snprintf so you can pass the size of your buffer to it, which will help prevent buffer overflows:
const int bufsize = 80;
char numString[bufsize] = { };
int charcheck = snprintf(numString, bufsize - 1, "%d", numCheck);
Notice that you subtract one from the buffer size that you pass to snprintf because you don't want it to use the very last slot, which you want to make sure is NULL to denote the end of the string.
You need to allocate space for the result such as
char numString[50];
int charcheck = sprintf(numString, "%d", numCheck);
In your case the interal workings of sprintf are trying to reference NULL which is the default value for a pointer in your case.
The most straightforward thing to do is to use an array as above, e.g.,
char numString[80] = { };
suggested by Seth, Jesus and Kerrek.
I think the last answer from sth is a good explanation: "the first parameter to sprintf is expected to point to a memory location where sprintf should write the formatted string." So apart from using an array of characters, which would force the allocation of memory for the string, you can also use this:
char *numstring = (char*) malloc(80);
This should let you explicitly free the allocated memory when it is no longer needed.

pass strings by reference in C

I'm having trouble figuring out how to pass strings back through the parameters of a function. I'm new to programming, so I imagine this this probably a beginner question. Any help you could give would be most appreciated. This code seg faults, and I'm not sure why, but I'm providing my code to show what I have so far.
I have made this a community wiki, so feel free to edit.
P.S. This is not homework.
This is the original version
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void
fn(char *baz, char *foo, char *bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
foo = malloc(strlen(pch));
strcpy(foo, pch);
pch = strtok (NULL, ":");
bar = malloc(strlen(pch));
strcpy(bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, myfoo, mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
}
UPDATE Here's an updated version with some of the suggestions implemented:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLINE 1024
void
fn(char *baz, char **foo, char **bar)
{
char line[MAXLINE];
char *pch;
strcpy(line, baz);
pch = strtok (line, ":");
*foo = (char *)malloc(strlen(pch)+1);
(*foo)[strlen(pch)] = '\n';
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = (char *)malloc(strlen(pch)+1);
(*bar)[strlen(pch)] = '\n';
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
First thing, those mallocs should be for strlen(whatever)+1 bytes. C strings have a 0 character to indicate the end, called the NUL terminator, and it isn't included in the length measured by strlen.
Next thing, strtok modifies the string you're searching. You are passing it a pointer to a string which you're not allowed to modify (you can't modify literal strings). That could be the cause of the segfault. So instead of using a pointer to the non-modifiable string literal, you could copy it to your own, modifiable buffer, like this:
char mybaz[] = "hello:world";
What this does is put a size 12 char array on the stack, and copy the bytes of the string literal into that array. It works because the compiler knows, at compile time, how long the string is, and can make space accordingly. This saves using malloc for that particular copy.
The problem you have with references is that you're currently passing the value of mybaz, myfoo, and mybar into your function. You can't modify the caller's variables unless you pass a pointer to myfoo and mybar. Since myfoo is a char*, a pointer to it is a char**:
void
fn(char *baz, char **foo, char **bar) // take pointers-to-pointers
*foo = malloc(...); // set the value pointed to by foo
fn(mybaz, &myfoo, &mybar); // pass pointers to myfoo and mybar
Modifying foo in the function in your code has absolutely no effect on myfoo. myfoo is uninitialised, so if neither of the first two things is causing it, the segfault is most likely occurring when you come to print using that uninitialised pointer.
Once you've got it basically working, you might want to add some error-handling. strtok can return NULL if it doesn't find the separator it's looking for, and you can't call strlen with NULL. malloc can return NULL if there isn't enough memory, and you can't call strcpy with NULL either.
One thing everyone is overlooking is that you're calling strtok on an array stored in const memory. strtok writes to the array you pass it so make sure you copy that to a temporary array before calling strtok on it or just allocate the original one like:
char mybaz[] = "hello:world";
Ooh yes, little problem there.
As a rule, if you're going to be manipulating strings from inside a function, the storage for those strings had better be outside the function. The easy way to achieve this is to declare arrays outside the function (e.g. in main()) and to pass the arrays (which automatically become pointers to their beginnings) to the function. This works fine as long as your result strings don't overflow the space allocated in the arrays.
You've gone the more versatile but slightly more difficult route: You use malloc() to create space for your results (good so far!) and then try to assign the malloc'd space to the pointers you pass in. That, alas, will not work.
The pointer coming in is a value; you cannot change it. The solution is to pass a pointer to a pointer, and use it inside the function to change what the pointer is pointing to.
If you got that, great. If not, please ask for more clarification.
In C you typically pass by reference by passing 1) a pointer of the first element of the array, and 2) the length of the array.
The length of the array can be ommitted sometimes if you are sure about your buffer size, and one would know the length of the string by looking for a null terminated character (A character with the value of 0 or '\0'.
It seems from your code example though that you are trying to set the value of what a pointer points to. So you probably want a char** pointer. And you would pass in the address of your char* variable(s) that you want to set.
You're wanting to pass back 2 pointers. So you need to call it with a pair of pointers to pointers. Something like this:
void
fn(char *baz, char **foo, char **bar) {
...
*foo = malloc( ... );
...
*bar = malloc( ... );
...
}
the code most likely segfaults because you are allocating space for the string but forgetting that a string has an extra byte on the end, the null terminator.
Also you are only passing a pointer in. Since a pointer is a 32-bit value (on a 32-bit machine) you are simply passing the value of the unitialised pointer into "fn". In the same way you wouldn't expact an integer passed into a function to be returned to the calling function (without explicitly returning it) you can't expect a pointer to do the same. So the new pointer values are never returned back to the main function. Usually you do this by passing a pointer to a pointer in C.
Also don't forget to free dynamically allocated memory!!
void
fn(char *baz, char **foo, char **bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
*foo = malloc(strlen(pch) + 1);
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = malloc(strlen(pch) + 1);
strcpy(*bar, pch);
return;
}
int
main(void)
{
char *mybaz, *myfoo, *mybar;
mybaz = "hello:world";
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free( myFoo );
free( myBar );
}
Other answers describe how to fix your answer to work, but an easy way to accomplish what you mean to do is strdup(), which allocates new memory of the appropriate size and copies the correct characters in.
Still need to fix the business with char* vs char**, though. There's just no way around that.
The essential problem is that although storage is ever allocated (with malloc()) for the results you are trying to return as myfoo and mybar, the pointers to those allocations are not actually returned to main(). As a result, the later call to printf() is quite likely to dump core.
The solution is to declare the arguments as ponter to pointer to char, and pass the addresses of myfoo and mybar to fn. Something like this (untested) should do the trick:
void
fn(char *baz, char **foo, char **bar)
{
char *pch;
/* this is the part I'm having trouble with */
pch = strtok (baz, ":");
*foo = malloc(strlen(pch)+1); /* include space for NUL termination */
strcpy(*foo, pch);
pch = strtok (NULL, ":");
*bar = malloc(strlen(pch)+1); /* include space for NUL termination */
strcpy(*bar, pch);
return;
}
int
main(void)
{
char mybaz[] = "hello:world";
char *myfoo, *mybar;
fn(mybaz, &myfoo, &mybar);
fprintf(stderr, "%s %s", myfoo, mybar);
free(myfoo);
free(mybar);
}
Don't forget the free each allocated string at some later point or you will create memory leaks.
To do both the malloc() and strcpy() in one call, it would be better to use strdup(), as it also remembers to allocate room for the terminating NUL which you left out of your code as written. *foo = strdup(pch) is much clearer and easier to maintain that the alternative. Since strdup() is POSIX and not ANSI C, you might need to implement it yourself, but the effort is well repaid by the resulting clarity for this kind of usage.
The other traditional way to return a string from a C function is for the caller to allocate the storage and provide its address to the function. This is the technique used by sprintf(), for example. It suffers from the problem that there is no way to make such a call site completely safe against buffer overrun bugs caused by the called function assuming more space has been allocated than is actually available. The traditional repair for this problem is to require that a buffer length argument also be passed, and to carefully validate both the actual allocation and the length claimed at the call site in code review.
Edit:
The actual segfault you are getting is likely to be inside strtok(), not printf() because your sample as written is attempting to pass a string constant to strtok() which must be able to modify the string. This is officially Undefined Behavior.
The fix for this issue is to make sure that bybaz is declared as an initialized array, and not as a pointer to char. The initialized array will be located in writable memory, while the string constant is likely to be located in read-only memory. In many cases, string constants are stored in the same part of memory used to hold the executable code itself, and modern systems all try to make it difficult for a program to modify its own running code.
In the embedded systems I work on for a living, the code is likely to be stored in a ROM of some sort, and cannot be physically modified.

Resources