Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
Solved

# Reuse pointer after free() -- double free error

Posted on 2011-03-01
Medium Priority
703 Views
Hi *,

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
0
Question by:James_h1023
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• Learn & ask questions
• 7
• 7
• 3
• +2

LVL 40

Expert Comment

ID: 35007570
>> I think it is safe to reuse pointers after freeing them (right?).
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.
0

LVL 46

Expert Comment

ID: 35007576
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
0

LVL 4

Author Comment

ID: 35007620
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
0

LVL 46

Expert Comment

ID: 35007715
Hi James,

What are you seeing that says "double free"?

Kent
0

LVL 40

Expert Comment

ID: 35007747
>> 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.
0

LVL 32

Expert Comment

ID: 35007929
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;
}
``````
0

LVL 4

Author Comment

ID: 35008945
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
``````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;
}
``````
0

LVL 32

Expert Comment

ID: 35008990
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.
0

LVL 4

Author Comment

ID: 35009067
Thanks.

I have done this, however am still getting the double free problem.

Cheers,
James
0

LVL 4

Author Comment

ID: 35009091
That is a lie ... I now get free(): invalid next size (fast) on the second Free_ ...
0

LVL 32

Expert Comment

ID: 35009146
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.

``````#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);
}
``````
0

LVL 4

Author Comment

ID: 35009227
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
0

LVL 46

Expert Comment

ID: 35009900
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
0

LVL 32

Expert Comment

ID: 35009941
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):
``````   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.
0

LVL 32

Expert Comment

ID: 35010225
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:
``````   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
0

LVL 32

Expert Comment

ID: 35012037
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.
0

LVL 4

Author Comment

ID: 35015770
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
``````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;
}
``````
0

LVL 32

Accepted Solution

phoffric earned 2000 total points
ID: 35015984
gdb should help (I never use it; I prefer graphical debugger such as ddd or netbeans - in one case, I found ddd better in identifying a problem). The data graphical features of ddd are very useful. If you do not have it, I recommend that you download it.

Your Free_2D_int_Array still has problems in that after you free, you are derefercing.

I'm not really sure that you need to set v to NULL or to fix the autovariable issue that I brought up. But if you really want to have the caller see a null pointer, then rather than deal with *** (I think ** is already complicated enough), why not just return the pointer:
`````` int** Free_2D_int_Array(int** v) {
free(v[0]);
v[0] = NULL;
free(v);
v = NULL;
return v;
}
// main():
...
v = Free_2D_int_Array(v);  // after return from function, v will be NULL
}
``````
As mentioned earlier, I like to think of a 2d array as a matrix having nRows and nCols (replacing dim1 and dim2, respectively).
How many row pointers have you allocated for v in line 3?
v = (int**)calloc(dim1, sizeof(int*));
When writing v[ i ], what is the range of valid i ?

In lines 12-13 you are looping over nCol pointers:
for (i=1; i<dim2; i++) {
v[ i ] = v[i-1] + dim2;
Compare this with my earlier comment, "But, in the loop, you have to set the remaining (nRows - 1) row pointers."
0

LVL 35

Expert Comment

ID: 35027821
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

0

LVL 4

Author Closing Comment

ID: 35226379
Apologies for the sever delay.

Many thanks,
James
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ouâ€¦
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and infâ€¦
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
###### Suggested Courses
Course of the Month7 days, 16 hours left to enroll

#### 715 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.