Basically, I am creating 2D array of struct using calloc(). Then I utilize that array and I free that allocated space, while freeing it I am getting "double free or corruption (!prev)". Code is written in C language.
Code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <fcntl.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <float.h>
typedef struct complex_num{
double real;
double imag;
}comp;
void transpose(comp *arr, int height, int width);
void change(comp *arr, int width);
void main(){
int width = 64, height = 64;
int len = width;
comp *fft[len];
for(int i=0; i<len; i++){
fft[i] = (comp *)calloc(len, sizeof(comp));
}
for (int scan=0;scan<height;scan++){
for (int pix=0;pix<width;pix++){
fft[scan][pix].real = 1.0;
fft[scan][pix].imag = 0.0;
}
change(&fft[scan][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
change(&fft[i][0], len);
}
transpose(&fft[0][0], len, len);
for(int i=0;i<len;i++){
free(fft[i]);
}
}
void transpose(comp *arr, int height, int width){
comp var;
for(int i=0;i<height;i++){
for(int j=0;j<width;j++){
if(j>i){
var = *((arr + (i*width)) + j);
*((arr + i*width) + j) = *((arr + j*width) + i);
*((arr + j*width) + i) = var;
}
}
}
}
void change(comp *arr, int width){
for(int i=0; i<width; i++){
(arr + i)->real = 5.0;
(arr + i)->imag = 6.9;
}
}
Error message:
*** Error in `./a.out': double free or corruption (!prev): 0x0000000002095010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f05108a77e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f05108b037a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f05108b453c]
./a.out[0x400880]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f0510850830]
./a.out[0x400509]
======= Memory map: ========
00400000-00401000 r-xp 00000000 00:00 467935 /path/to/a.out
00600000-00601000 r--p 00000000 00:00 467935 /path/to/a.out
00601000-00602000 rw-p 00001000 00:00 467935 /path/to/a.out
02095000-020b6000 rw-p 00000000 00:00 0 [heap]
7f050c000000-7f050c021000 rw-p 00000000 00:00 0
7f050c021000-7f0510000000 ---p 00000000 00:00 0
7f0510610000-7f0510626000 r-xp 00000000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510626000-7f0510825000 ---p 00000016 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510825000-7f0510826000 rw-p 00015000 00:00 360788 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0510830000-7f05109f0000 r-xp 00000000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f0000-7f05109f9000 ---p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f05109f9000-7f0510bf0000 ---p 000001c9 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf0000-7f0510bf4000 r--p 001c0000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf4000-7f0510bf6000 rw-p 001c4000 00:00 360750 /lib/x86_64-linux-gnu/libc-2.23.so
7f0510bf6000-7f0510bfa000 rw-p 00000000 00:00 0
7f0510c00000-7f0510c25000 r-xp 00000000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510c25000-7f0510c26000 r-xp 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e25000-7f0510e26000 r--p 00025000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e26000-7f0510e27000 rw-p 00026000 00:00 360690 /lib/x86_64-linux-gnu/ld-2.23.so
7f0510e27000-7f0510e28000 rw-p 00000000 00:00 0
7f0510e30000-7f0510e31000 rw-p 00000000 00:00 0
7f0510e40000-7f0510e41000 rw-p 00000000 00:00 0
7f0510e50000-7f0510e51000 rw-p 00000000 00:00 0
7f0510e60000-7f0510e61000 rw-p 00000000 00:00 0
7fffc47c7000-7fffc4fc7000 rw-p 00000000 00:00 0 [stack]
7fffc5242000-7fffc5243000 r-xp 00000000 00:00 0 [vdso]
I am compiling my code with GCC version 5.4.0. I don't understand the error message and don't know how to debug it. What should I do to free the array of pointers?
transpose
blatantly accesses elements outside of the array bounds.
fft
in main
is an array of pointers. Each pointer is initialized to point to a block of dynamically allocated memory (via calloc
).
It looks like this in memory:
0 1 63
fft: 0 [ 0x0000a000 ] ----> [ real; imag | real; imag | ... | real; imag ]
1 [ 0x0000ff08 ] ----> [ real; imag | real; imag | ... | real; imag ]
.
.
.
63 [ 0x0001041c ] ----> [ real; imag | real; imag | ... | real; imag ]
fft
has 64 elements, each of which is a pointer. In this example, fft[0]
has the value 0x0000a000
, at which address there is another 64-element array (created by calloc
), which stores values of type comp
(which is a 2-element struct).
Thus *fft[0]
is the first comp
struct (at address 0x0000a000
), *fft[1]
is the second comp
struct (at address 0x0000a010
), *fft[2]
is the third comp
struct (at address 0x0000a020
), etc. Each comp
struct takes 16 bytes, so the addresses increase by 16 (0x10). The last element of fft[0]
, fft[0][63]
lives at address 0x0000a3f0
.
fft[1]
is the second pointer, pointing to a second (unrelated) block of memory (also created by calloc
). In this example the instances of comp
live at addresses 0x0000ff08
, 0x0000ff18
, 0x0000ff28
, etc.
The same thing happens for all elements of fft
, up to fft[63]
. In this example the comp
instances fft[63][0]
, fft[63][1]
, fft[63][2]
, etc. live at addresses 0x0001041c
, 0x0001042c
, 0x0001043c
, etc.
Now consider what transpose
does. It is called like this:
transpose(&fft[0][0], len, len);
It accesses memory like this:
*((arr + (i*width)) + j)
Here arr
is the first parameter; its value is &fft[0][0]
, which is the same as fft[0]
, which in our example is 0x0000a000
.
width
is 64. i
and j
are somewhere between 0 and 63, depending on which loop iteration we're in. Let's assume they're at 63.
Then i*width
is 63*64
is 4032
, and arr + 4032
is a pointer to the 4033rd element of the array. But wait! There is no such element; arr
only has 64 elements.
We're now at memory address 0x00019c00
, which is far outside the bounds of fft[0]
(recall that its elements only go up to address 0x000a3f0
).
But we're not done yet: To this pointer we add j
(63), giving 0x00019ff0
. And this pointer is what we dereference with *
.
Had we written this operation using array notation, it would have looked like
arr[i*width + j]
which more obviously shows that we're accessing element 4095 of a 64-element array.
transpose
even writes to this address:
*((arr + i*width) + j) = ...
This modifies memory that your program doesn't own, thus corrupting the internal data structures used by malloc
/ calloc
/ free
. That's what the error message double free or corruption
means: Your code has corrupted data that was needed for free
, which can happen by freeing the same pointer twice ("double free") or just writing to memory past the end of your arrays (as in your code).
To fix your code, change transpose
to
void transpose(comp **arr, int height, int width) {
for (int i = 0 ; i < height; i++) {
for (int j=0; j < width; j++) {
if (j > i) {
comp var = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = var;
}
}
}
}
and call it as
transpose(fft, len, len);
This way you don't just pass the address of the first sub-array, but the address of the intermediate pointer array (which in turn lets you access any of the 64 sub-arrays).