Member_2_2394978
asked on
Reuse pointer after free() -- double free error
Hi *,
I think it is safe to reuse pointers after freeing them (right?). For exmaple,
EDIT: that is a lie, it also gives a double free. Why?
However, I get a double free error from
where
Any suggestions?
Cheers,
James
I think it is safe to reuse pointers after freeing them (right?). For exmaple,
float* t = (float*)calloc(100, sizeof(float));
free(t);
t = (float*)calloc(100, sizeof(float));
free(t);
works fine.EDIT: that is a lie, it also gives a double free. Why?
However, I get a double free error from
float** v;
v = Get_2D_FloatArray(10, 10);
Free_2D_FloatArray(v);
v = Get_2D_FloatArray(10, 10);
Free_2D_FloatArray(v);
where
int** Get_2D_Int-Array(int dim1, int dim2) {
int** v;
v = (int**)calloc(dim2, sizeof(int*));
v[0] = (int*)calloc(dim1*dim2, sizeof(int));
int i=0;
for (i=1; i<dim1; i++) {
v[i] = v[i-1] + dim2;
}
return v;
}
void Free_2D_int_Array(int** v) {
free(v[0]);
free(v);
v[0] = NULL;
v = NULL;
}
Any suggestions?
Cheers,
James
Hi James,
You can always reuse pointers. As far as the program is concerned, they are just variables. (Their contents just happens to be an address in memory instead of a "normal"item like an integer or character.)
It's a good idea to set the pointer to 0 (NULL) after freeing it. This makes it easy for the program to track valid/obsolete pointers. Most free() functions disregard the attempt to free memory when the passed value is NULL so if the program does try to free the same memory twice, having set the pointer to NULL after the first call to free() gets you past the error.
Good Luck,
Kent
You can always reuse pointers. As far as the program is concerned, they are just variables. (Their contents just happens to be an address in memory instead of a "normal"item like an integer or character.)
It's a good idea to set the pointer to 0 (NULL) after freeing it. This makes it easy for the program to track valid/obsolete pointers. Most free() functions disregard the attempt to free memory when the passed value is NULL so if the program does try to free the same memory twice, having set the pointer to NULL after the first call to free() gets you past the error.
Good Luck,
Kent
ASKER
Thanks for quick responses.
I thought it was safe to re-use them. As you say they are just variables.
So, why does my code produce a double free?
Cheers,
James
I thought it was safe to re-use them. As you say they are just variables.
So, why does my code produce a double free?
Cheers,
James
Hi James,
What are you seeing that says "double free"?
Kent
What are you seeing that says "double free"?
Kent
>> As you say they are just variables.
Indeed, variables that are specifically designed to hold address values just as (for example) an int is specifically designed to hold a numeric value.
I can see Kent is here so I'll leave you guys to work on this.
Good luck.
Indeed, variables that are specifically designed to hold address values just as (for example) an int is specifically designed to hold a numeric value.
I can see Kent is here so I'll leave you guys to work on this.
Good luck.
You must not deference a pointer after freeing it. Swap two lines.
void Free_2D_int_Array(int** v) {
free(v[0]); // OK
free(v); // you free v here
v[0] = NULL; // now you are dereferencing v after freeing it
v = NULL;
}
ASKER
Hmm ok that makes sense.
I have updated my get function to the attached, to check whether I am allocating memory okay, and I am.
Kent: on my second call to Free_2D_FloatArray(v); (line 5 in my first code attachement in first post) I get
*** glibc detected *** double free or corruption (out): 0x ... *
phoffric: I still get my double free error with both the NULL lines commented. But I would like them in, so how could I reorder them?
Cheers,
James
I have updated my get function to the attached, to check whether I am allocating memory okay, and I am.
Kent: on my second call to Free_2D_FloatArray(v); (line 5 in my first code attachement in first post) I get
*** glibc detected *** double free or corruption (out): 0x ... *
phoffric: I still get my double free error with both the NULL lines commented. But I would like them in, so how could I reorder them?
Cheers,
James
int** Get_2D_Int-Array(int dim1, int dim2) {
int** v;
v = (int**)calloc(dim2, sizeof(int*));
if (v == NULL) {
return NULL;
}
v[0] = (int*)calloc(dim1*dim2, sizeof(int));
if (v[0] == NULL) {
return NULL;
}
int i=0;
for (i=1; i<dim1; i++) {
v[i] = v[i-1] + dim2;
}
return v;
}
void Free_2D_int_Array(int** v) {
free(v[0]);
free(v);
v[0] = NULL;
v = NULL;
}
If you swap lines 20 and 21, then that should help.
This way you free v[0], and then set v[0] to NULL. So now you are dereferencing v before you free it - OK.
Then you free v, and then set v to NULL - OK.
This way you free v[0], and then set v[0] to NULL. So now you are dereferencing v before you free it - OK.
Then you free v, and then set v to NULL - OK.
ASKER
Thanks.
I have done this, however am still getting the double free problem.
Cheers,
James
I have done this, however am still getting the double free problem.
Cheers,
James
ASKER
That is a lie ... I now get free(): invalid next size (fast) on the second Free_ ...
What I wrote is a fix to a definite problem that you have, but I just realized that you commented out had commented out lines 21 and 22, so you have more than one problem.
You may have other corruption issues in your larger program, but as a test, could you see if this standalone program runs without error.
You may have other corruption issues in your larger program, but as a test, could you see if this standalone program runs without error.
#include <stdlib.h>
int** Get_2D_Int_Array(int dim1, int dim2) {
int** v;
v = (int**)calloc(dim2, sizeof(int*));
v[0] = (int*)calloc(dim1*dim2, sizeof(int));
int i=0;
for (i=1; i<dim1; i++) {
v[i] = v[i-1] + dim2;
}
return v;
}
void Free_2D_int_Array(int** v) {
free(v[0]);
v[0] = NULL;
free(v);
v = NULL;
}
int main()
{
int** v;
v = Get_2D_Int_Array(10, 10);
Free_2D_int_Array(v);
v = Get_2D_Int_Array(10, 10);
Free_2D_int_Array(v);
}
ASKER
I've found it ...
it works as long as the dimensions are the same both times ... so 10, 10 and 10, 10, however I am (my fault, I didn't include it in here) doing 10, 10 the first time and 1000, 10 the second time. Does this make a difference?
The simple example you gave works for, as I say, the same dimensions, but not for different ones.
Cheers,
James
it works as long as the dimensions are the same both times ... so 10, 10 and 10, 10, however I am (my fault, I didn't include it in here) doing 10, 10 the first time and 1000, 10 the second time. Does this make a difference?
The simple example you gave works for, as I say, the same dimensions, but not for different ones.
Cheers,
James
Hi James,
The size doesn't matter, as long as the program only references the memory in the current size. That is if you allocate 1,000 bytes, free it, allocate 1,000,000 bytes, free it, and the allocation 5,000 bytes, byte 100,000 is valid only between the 2nd and 3rd allocations.
Kent
The size doesn't matter, as long as the program only references the memory in the current size. That is if you allocate 1,000 bytes, free it, allocate 1,000,000 bytes, free it, and the allocation 5,000 bytes, byte 100,000 is valid only between the 2nd and 3rd allocations.
Kent
In my earlier post, I just immediately noticed a pointer problem which is now cleared up.
>> I am doing 10, 10 the first time and 1000, 10 the second time. Does this make a difference?
The problem is not that you are doing these two things in succession. You have a problem even if you do not do 10, 10. Just do 1000, 10.
Now, what debugger do you have available? Do you have one that can show multiple memory regions? That would help you.
This single line results in erroneous code (which may or not show up as an immediate error - platform dependent):
>> I am doing 10, 10 the first time and 1000, 10 the second time. Does this make a difference?
The problem is not that you are doing these two things in succession. You have a problem even if you do not do 10, 10. Just do 1000, 10.
Now, what debugger do you have available? Do you have one that can show multiple memory regions? That would help you.
This single line results in erroneous code (which may or not show up as an immediate error - platform dependent):
v = Get_2D_Int_Array(1000, 10);
In Get_2D_Int_Array, dim1 is 1000 and dim2 is 10. Here you are allocating a region suitable for 10 pointers. v = (int**)calloc(dim2, sizeof(int*));
But then here you are setting 1000 pointers: for (i=1; i<dim1; i++)
v[i] = v[i-1] + dim2;
which goes beyond the allocated region.
The main problem, then, is not freeing twice, but overwriting memory that was not allocated to you.
When dealing with memory allocation errors, the actual errors reported can be very misleading, and the detection of a problem will vary from one system to another. In fact, it is possible that some errors will not be immediately detected until you make a small change to a different part of the program.
Now doing this probably will not cause an error:
You should consider another design for dynamically creating 2d arrays. Here is one approach: http://rdsrc.us/IApazh
You can get a good deal of useful practical information from this EE search: http://rdsrc.us/CxPzLP
When dealing with memory allocation errors, the actual errors reported can be very misleading, and the detection of a problem will vary from one system to another. In fact, it is possible that some errors will not be immediately detected until you make a small change to a different part of the program.
Now doing this probably will not cause an error:
v = Get_2D_Int_Array(10, 10);
Free_2D_int_Array(v);
v = Get_2D_Int_Array(10, 1000);
Free_2D_int_Array(v);
I did notice one other interesting syntactical issue. In Free_2D_int_Array, you set v to NULL; but v is an auto variable in Free_2D_int_Array's stack. So, when you return to main, the v there should not be affected.You should consider another design for dynamically creating 2d arrays. Here is one approach: http://rdsrc.us/IApazh
You can get a good deal of useful practical information from this EE search: http://rdsrc.us/CxPzLP
Often, we see a 2d matrix described as nRows x nCols, which would correspond to your dim1 and dim2, respectively. Then to set up the matrix using your code, first allocate enough space for nRows row pointers. So, v[ i ] are pointers to the start of each row. You can allocate v[0] as you have done. But, in the loop, you have to set the remaining (nRows - 1) row pointers.
ASKER
Morning (here),
Many thanks for your responses.
I have swapped dim1 and dim2, and indeed that did fix my error, and now I have the attached (I also fixed my automatic variable problem, I think?)
I used this approach over the one you linked for less allocations and more contiguous memory (this is related to a previous question, where I must have change the 3d version to a 2d version incorrectly, i.e. having dim1 and dim2 around the wrong way: previous question.
But it is still "double freeing" randomly. Some times it works fine, other times not, other times fine.
Firstly, I suppose, is the code attached fine now? I may be doing something somewhere else (although i'm pretty sure not).
I have gdb available, will that help? I must admit the only thing I can do with it, is put breaks in and evaluate variables!
Cheers,
James
Many thanks for your responses.
I have swapped dim1 and dim2, and indeed that did fix my error, and now I have the attached (I also fixed my automatic variable problem, I think?)
I used this approach over the one you linked for less allocations and more contiguous memory (this is related to a previous question, where I must have change the 3d version to a 2d version incorrectly, i.e. having dim1 and dim2 around the wrong way: previous question.
But it is still "double freeing" randomly. Some times it works fine, other times not, other times fine.
Firstly, I suppose, is the code attached fine now? I may be doing something somewhere else (although i'm pretty sure not).
I have gdb available, will that help? I must admit the only thing I can do with it, is put breaks in and evaluate variables!
Cheers,
James
int** Get_2D_Int-Array(int dim1, int dim2) {
int** v;
v = (int**)calloc(dim1, sizeof(int*));
if (v == NULL) {
return NULL;
}
v[0] = (int*)calloc(dim1*dim2, sizeof(int));
if (v[0] == NULL) {
return NULL;
}
int i=0;
for (i=1; i<dim2; i++) {
v[i] = v[i-1] + dim2;
}
return v;
}
void Free_2D_int_Array(int*** v) {
free(*v[0]);
free(*v);
*v[0] = NULL;
*v = NULL;
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
in line 12 the for loop should go from 1 to dim1 - 1 (and not dim2) cause you allocated dim1 "rows".
in line 20 and 21 you shouldn't dereference cause the pointers were freed.
look at phoffric's code it is fine. or omit the setting to NULL. it makes not so much sense cause it is local variables only.
Sara
in line 20 and 21 you shouldn't dereference cause the pointers were freed.
look at phoffric's code it is fine. or omit the setting to NULL. it makes not so much sense cause it is local variables only.
Sara
ASKER
Apologies for the sever delay.
Many thanks,
James
Many thanks,
James
A pointer is just a data-type, it can be re-assigned a value at any time (regardless of whether you free malloc/calloc allocated memory to it or not). The only requirement if you allocated from the heap is that at some point you free it.... but it don't have to be via the original pointer that the address was assigned too.
If you are getting a double free error you must be calling free on the same address more than once.