Freeing a pointer by dereferencing a doublepointer in C [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
I'm trying to write a function which will free a dynamically allocated string by sending the address of the string (char*) to the function. (Sending char**)
I have tried doing it like this:
void dstring_delete(DString* stringToDelete)
{
// Precondition: stringToDelete is not NULL
assert(stringToDelete != NULL);
free(*stringToDelete);
Where DString is defined like this:
typedef char* DString;
The call to the function looks like this:
dstring_delete(&str1);
Where str1 is of type DString:
DString str1, str2;
I cant seem to figure out what is going wrong but this assert below the function call fails:
assert(str1 == NULL);
So my question is how I properly free the memory in this instance.
I have tried different arguments sent to the free function and also tried to find the same issues here.

I assume that str1 is pointing to an allocated block that is to be freed and that the code sequence to free the block is like this:
dstring_delete(&str1);
assert(str1 == NULL);
OP's implementation of dstring_delete seems to be as follows, but OP did not post the full function definition including the closing brace:
void dstring_delete(DString* stringToDelete)
{
// Precondition: stringToDelete is not NULL
assert(stringToDelete != NULL);
free(*stringToDelete);
}
It is not very clear from OP's question, but I think their code contains the following sequence, with str1 pointing to a previously allocated block to be freed:
dstring_delete(&str1);
assert(str1 == NULL);
OP wrote that the assert(str1 == NULL); was failing. This is because dstring_delete does not change the value of *stringToDelete (which aliases the str1 variable) so *stringToDelete (and the str1 variable) will still contain a non-null value on return from the function. However, the assert(str1 == NULL); implies that it is expecting dstring_delete to set the pointer value to NULL. That is easily fixed by changing the function body of dstring_delete to set the pointer to NULL after freeing the allocated block:
void dstring_delete(DString* stringToDelete)
{
// Precondition: stringToDelete is not NULL
assert(stringToDelete != NULL);
free(*stringToDelete);
*stringToDelete = NULL;
}
Now, after the function call dstring_delete(&str1);, str1 will be NULL so the assert(str1 == NULL); call will pass.

The variable name of a string is itself a memory reference to the string; the type is char pointer and so the variable contains a pointer, which is a memory address. So when you call free() you only have to pass it the name of the variable.
(If you use the "&" you are passing the memory address where the string's memory address is located, and you only need the latter.)

Related

Why can I reposition a pointer given as an argument to a function but not reassign a new value to it after `realloc`?

In this question I'm referring to another stackoverflow question because I don't have enough points to comment it.
See: Valgrind Reports Invalid Realloc
In short: Why must the instruction buffer = trim(buffer); be written outside the function? Why can't it be written inside the function as phrase = (char*)realloc(phrase, strlen(phrase)+1);?
In depth: Assuimng I pass any pointer to a function - such as const *str; - then by executing str++; I can create a side effect and change the starting position of the string.
But why can't I just reassign another value to the function through dynamic memory management functions such as malloc and realloc?
Why can't I just set str = (char*) realloc(str, strlen(str) + 1 * sizeof(char));?
What makes this side effect different from the other one?
Couldn't I hypothetically just move str where ever I want to?
C passes all arguments by value. Look at the parameters of a called function like local variables of this function, initialized by copies of the arguments given by the caller.
We can "emulate" pass by reference, if we pass a pointer. By dereferencing the pointer, we can access the "referenced" object living outside the called function. But this pointer is still passed by value, meaning it is a copy of the argument, initializing the parameter.
Note: The references of C++ and other languages are nothing else than pointers, under the hood. There are additional semantics, though. You might want to look at generated machine code.
So you can do anything you want with that pointer in the parameter, overwrite it, increment or decrement it, even NULL it. This has no effect of the source of the pointer in the caller.
The problem of the question you link can be boiled down to:
char* called(char* pointer)
{
return realloc(pointer, /* some irrelevant value */);
}
void caller(void)
{
char* buffer = malloc(/* some irrelevant value */);
/* ignore returned pointer */ called(buffer);
free(buffer); /* here Valgrind reports an error */
}
We need to differentiate multiple cases for realloc() here.
realloc() returns NULL, because there is not enough memory to satisfy the request. The former address is still valid.
realloc() returns the same address, because it can satisfy the request this way. Since returned and former address are equal, both are valid.
realloc() returns a new address. The former address is now invalid.
Of these, the third case is the common one, and it leads to the documented issue.
Because buffer in caller() is not changed by called(), simply because called() cannot access it, it still holds the former address. Now when free() is called with this invalid address, the error is detected.
To correct this error, caller() needs to use the returned value. The Right WayTM to do this is:
void caller(void)
{
char* buffer = malloc(/* some irrelevant value */);
char* new_buffer = called(buffer);
if (new_buffer != NULL) {
buffer = new_buffer;
} else {
/* handle the re-allocation error, the address in buffer is still valid */
}
free(buffer);
}
An alternative is to pass the pointer to buffer to called() and let it modify buffer correctly. But this type of redirection often generates worse readable code. However, for a convenience function you might decide to go this route.

How to use realloc in C [duplicate]

This question already has answers here:
Expanding an array with malloc
(4 answers)
In C, are arrays pointers or used as pointers?
(6 answers)
Closed 2 years ago.
I'm trying to reallocate memory using the realloc function, I saw that you need to use malloc before but I don't understand if you MUST use it because let's say I'm creating the following string:
char string[] = "fun";
would the realloc function work if I try to add more space?
that brings me to my question, I'm trying to simply add one letter at the end of the string, lets say 'p', but for some reason the program crushes on the realloc line every time I run it.
Here is my full code:
int main()
{
char string[] = "fun" ;
str_func(string);
printf("%s", string);
return 0;
}
void str_func(char* str)
{
str = (char*)realloc(str, strlen(str) + 2);
strcat(str, "p");
}
I also tried making a pointer to 'string' and sending the pointer, which results the same thing.
would the realloc function work if I try to add more space?
No, because that array is no allocated on the heap - in your case it is very likely allocated on the stack and can't get resized. Simply put: realloc doesn't recognize the pointer and doesn't know what to do with it, but tries to do something anyway, hence the crash.
You can only call realloc on a pointer that was previously passed to malloc, or on a null pointer. That's just how these functions work.
For details, see What gets allocated on the stack and the heap?.
I saw that you need to use malloc before but I don't understand if you MUST use it
If you need to use malloc before you can realloc something, then by definition you must only realloc things originally allocated with malloc.
You're trying to find some space between "need" and "must" that doesn't exist.
... for some reason the program crushes on the realloc
You already said you know you need to use malloc. Then you didn't use malloc, and you're asking why this is a problem. You could at least try doing the thing you "know" you need to do, to see if that solves the problem.
The program should probably look like
int main()
{
/* array is an automatic local variable. It wasn't dynamically allocated
in the first place, so can't be dynamically re-allocated either.
You cannot (and don't need to) free it either, it just goes out of scope
like any other automatic variable.
*/
char array[] = "fun";
/* you need to use malloc (or one of the other dynamic allocation functions)
before you can realloc, as you said yourself */
char *dynamic = malloc(1+strlen(array));
memcpy(dynamic, array, 1+strlen(array));
/* realloc can move your data, so you must use the returned address */
dynamic = str_func(dynamic);
printf("old:'%s', new:'%s'\n", array, dynamic);
/* not really essential since the program is about to exit anyway */
free(dynamic);
}
char* str_func(char* str)
{
char* newstr = realloc(str, strlen(str) + 2);
if (newstr) {
strcat(newstr, "p");
return newstr;
} else {
/* we failed to make str larger, but it is still there and should be freed */
return str;
}
}
Your original condition isn't quite correct: actually the pointer passed to realloc
... must be previously allocated by malloc(), calloc() or realloc() and not yet freed with a call to free or realloc
[OR] If ptr is NULL, the behavior is the same as calling malloc(new_size).
The realloc function only works with things that were originally created with a small group of allocation functions (such as malloc, calloc, or realloc itself), or the null pointer. Since string is none of those things, your code is not well-defined.

munmap_chunk() error in when i free an allocated memory [duplicate]

This question already has answers here:
how 'free' works when pointer is incremented
(9 answers)
Closed 4 years ago.
i have a char* path that is global, later i call a function that allocates memory and returns it, and path points to it, when i free it i get this error
the only way is to not free the pointer
void free_memory() {
if(path!=NULL)
free(path);//problem
}
char* ExtractPath(char*str)
{
char*temp=(char*)malloc(sizeof(char)*(strlen(str))+1);
bzero(temp,strlen(temp));
char ch ='/';
if( checkUrl(str)==1) {
if(strncasecmp(str,"http://",7)==0)
str+=7;
if(strstr(str,"/")!=NULL)
{
strcpy(temp,str);
temp=strchr(temp,ch);
strtok(temp,"\t");
}
else
strcpy(temp,"/");
}
return temp;
}
path=ExtractPath(Users_input);//here the pointer points to the allocated memory that returned from the function the char*path is a global value
As I see, the problem is with
bzero(temp,strlen(temp));
The content of temp is indeterminate, passing that to strlen() would invoke undefined behaviour.
Quoting C11, chapter §7.22.3.4
The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
That said, regarding the error for free() part, you have to supply the exact pointer which was returned by malloc() or family.
Quoting chapter §7.22.3.3
[...] Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
In your code, you actually modify the original pointer stored in temp by saying
temp=strchr(temp,ch);
strtok(temp,"\t");
and return the "modified" temp.
Passing that temp to free() will lead to undefined behaviour, once again.
Since ExtractPath does not return the value returned from malloc, there is no way to free the returned string. It is only legal to pass to free precisely the value you got back from malloc.
Once you do temp=strchr(temp,ch);, the original value returned from malloc is lost. Calling free on the value returned from strchr is not legal.
Here's one way to fix it:
char* ExtractPath(char*str)
{
char* temp=(char*)malloc(sizeof(char)*(strlen(str))+1);
char* orig = temp; /* save the value we got back from malloc */
char* ret;
char ch ='/';
if( checkUrl(str)==1) {
if(strncasecmp(str,"http://",7)==0)
str+=7;
if(strstr(str,"/")!=NULL)
{
strcpy(temp,str);
temp=strchr(temp,ch);
strtok(temp,"\t");
}
else
strcpy(temp,"/");
}
ret = malloc (strlen(temp) + 1);
strcpy(ret, temp); /* make a new copy to return */
free(orig); /* pass what malloc returned to free */
return ret; /* caller can free this since we got it back from malloc */
}

Simulating failure of calloc by setting char pointer to NULL

**** This question is very confused, because I missed something in my program, but the answers to this question are insightful (for me anyway). If you are having a similar problem, I would suggest that you focus on the answers rather than on my code ****
I am trying to write a program that can handle failure of memory allocation by informing the user of the failure, but working around it. (I understand that this is not the right thing to do in most situations).
I have a structure. One of its structure variables is:
char* name;
At some point, I have the following line, allocating memory for this variable dynamically and setting it to some input:
if(object->name = calloc(1, strlen(input)+1)){
strcpy(object->name, input);
}
I want to check behavior of the program in the case that calloc fails to allocate memory. I wrote a test where I replaced the above line of code with:
object->name = NULL; //instead of the calloc
Because I reckon that calloc will return NULL if it fails to allocate memory.
However, I get a segmentation fault on that line when I do it. I think it is because I have not allocated memory for object->name. However, that is precisely my point. I just want to set the pointer to the char array to be NULL. I want to check for this NULL pointer somewhere later in the program and work around it.
How would I make object->name a NULL pointer without getting the segmentation fault?
because I have not included enough detail above, this is the actual code:
//disk is the "object" in question
if(disk_ptr = calloc (1, sizeof (disk))){
disk_created_successfully = set_or_fix_disk_static_attributes_test_all_is_null(&disk_ptr, name);
...
}
Where
bool set_or_fix_disk_static_attributes_test_all_is_null(disk** disk_ptr, char* name){
int success = true;
(*disk_ptr)->name = NULL;
// Code fails here
...
return success;
}
To test the condition, you could change
if(object->name = calloc(1, strlen(input)+1)){
strcpy(object->name, input);
}
to
if (0) {
strcpy(object->name, input);
}
That is, your original code is checking that the allocation succeeds. The result of it failing is that "false" is the condition.
Probably there is other code which uses object->name, so a more comprehensive test is:
if (object->name = NULL) {
strcpy(object->name, input);
}
As far as I can see from your snippet, if object is allocated peroper memory,
object->name = NULL;
is fine and legal. However, in that case, at any later point, any code similar to
strcpy(object->name, input);
will be illegal, as you'll be essentially trying to write into invalid memory. in general, any subsequent access to read from and write to object->name should be blocked.
EDIT:
I think you're a bit confused. As your post says, if you're trying to simulate the calloc() failure, then you must be be setting the disk_ptr to NULL. Then, inside the set_or_fix_disk_static_attributes_test_all_is_null() function, the instruction
(*disk_ptr)->name = NULL;
is becoming invalid, as you'll be de-referencing the NULL pointer. You may want to add a check for the *disk_ptr against NULL first.
You need to test for a NULL pointer immediately after the call to calloc. If you reference that NULL pointer at any point you're asking for trouble.
In this case, that would be right after the point where you manually set your pointer to NULL.

Can I check if a pointer was allocated by malloc/calloc/realloc? [duplicate]

This question already has answers here:
Check if a pointer points to allocated memory on the heap
(10 answers)
Can you determine if a string if freeable in C? [duplicate]
(5 answers)
Closed 9 years ago.
I was wondering is it possible to check if a pointer passed into a function was allocated by malloc/calloc/realloc?
int main(){
struct something o;
struct something *a;
a = malloc(sizeof(struct something));
freeSome(&o);/*This would normally throw an (corruption?) error*/
freeSome(a);/*This is fine*/
}
void freeSome(struct something * t){
if (/*expression here*/){
free(t);
}
}
I understand that usually you check to see if t == NULL, but I was just wondering if it was possible to see if memory has been allocated for the given pointer.
No, you can't.
Basically, you should not need to do this. If you are wanting to write a helper function to free some memory given a pointer, than you should awarely and explicitely pass a dynamically allocated pointer to a certain area of memory to do so.
Raw pointers in C cannot transport extra informations about the memory they are pointing to. If you want to have such informations, you will have to pass an additional wrapper that holds the pointer you are interested in, such as :
typedef struct my_pointer
{
void *ptr;
int is_dynamically_allocated;
} ptr;
But this would be a huge loss of memory/time.
No way to check, you ought to NULL initialize and then test whether NULL indeed
From section 7.20.3.2 The free function of C99 standard:
The free function causes the space pointed to by ptr to be deallocated, that is,
made available for further allocation. If ptr is
a null pointer, no action occurs. Otherwise, if the argument does not
match a pointer earlier returned by the calloc, malloc, or realloc
function, or if the space has been deallocated by a call to free or
realloc, the behavior is undefined.

Resources