Question:
My intention is to free the memory allocated for the age
attribute of this code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct TEST test;
struct TEST
{
char* name;
int* age;
};
test test_new (test*, char*, int);
int
main (void)
{
test t;
int age = 13;
int* p_age = &age;
test_new (&t, "", *p_age);
printf ("Age [%i]\n", *t.age);
free (t.age);
return 0;
}
test test_new (test* _test, char* _name, int _age)
{
(*_test).age = (int *) malloc (1 * sizeof (int));
(*_test).age = &_age;
return (*_test);
}
Commenting on the line where I release free (t.age);
I get an untreated resource in valgrind :
==17683== total heap usage: 2 allocs, 1 frees, 1,028 bytes allocated
When assigning the code for the release of the resource I get this:
$ ./main7
Age [13]
*** Error in `./main7': free(): invalid pointer: 0x00007ffff2b0bebc ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777f5)[0x7f83261f17f5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8038a)[0x7f83261fa38a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f83261fe58c]
./main7[0x400686]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f832619a840]
./main7[0x400559]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:13 2745 /home/ubuntu/main7
00600000-00601000 r--p 00000000 08:13 2745 /home/ubuntu/main7
00601000-00602000 rw-p 00001000 08:13 2745 /home/ubuntu/main7
02305000-02326000 rw-p 00000000 00:00 0 [heap]
7f8320000000-7f8320021000 rw-p 00000000 00:00 0
7f8320021000-7f8324000000 ---p 00000000 00:00 0
7f8325f64000-7f8325f7a000 r-xp 00000000 00:19 12664 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8325f7a000-7f8326179000 ---p 00016000 00:19 12664 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f8326179000-7f832617a000 rw-p 00015000 00:19 12664 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f832617a000-7f832633a000 r-xp 00000000 00:19 12626 /lib/x86_64-linux-gnu/libc-2.23.so
7f832633a000-7f832653a000 ---p 001c0000 00:19 12626 /lib/x86_64-linux-gnu/libc-2.23.so
7f832653a000-7f832653e000 r--p 001c0000 00:19 12626 /lib/x86_64-linux-gnu/libc-2.23.so
7f832653e000-7f8326540000 rw-p 001c4000 00:19 12626 /lib/x86_64-linux-gnu/libc-2.23.so
7f8326540000-7f8326544000 rw-p 00000000 00:00 0
7f8326544000-7f832656a000 r-xp 00000000 00:19 12598 /lib/x86_64-linux-gnu/ld-2.23.so
7f832674a000-7f832674d000 rw-p 00000000 00:00 0
7f8326768000-7f8326769000 rw-p 00000000 00:00 0
7f8326769000-7f832676a000 r--p 00025000 00:19 12598 /lib/x86_64-linux-gnu/ld-2.23.so
7f832676a000-7f832676b000 rw-p 00026000 00:19 12598 /lib/x86_64-linux-gnu/ld-2.23.so
7f832676b000-7f832676c000 rw-p 00000000 00:00 0
7ffff2aee000-7ffff2b0f000 rw-p 00000000 00:00 0 [stack]
7ffff2b7b000-7ffff2b7e000 r--p 00000000 00:00 0 [vvar]
7ffff2b7e000-7ffff2b80000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)
Now if I take and comment //free (t.age);
and I put free (t.name);
and in the constructor that looks like this:
test test_new (test* _test, char* _name, int _age)
{
(*_test).name = (char *) malloc (1 * sizeof (char));
strcpy ((*_test).name, _name);
return (*_test);
}
Everything works wonderfully, I can see how the resource is completely released:
==17779== total heap usage: 2 allocs, 2 frees, 1,025 bytes allocated
What is happening here?
I initially started this exercise with int* age;
In the structure and in view of these errors I added another basic type to verify my suspicion and it turned out that I have a successful result in one, but in the other I do not have it.
Thanks for reading and commenting.
Answer:
The problem of your first test is in these lines:
(*_test).age = (int *) malloc (1 * sizeof (int));
(*_test).age = &_age;
In the first line you ask for memory with malloc and save the resulting pointer in (*_test).age
, then in the second line you overwrite it with a pointer to _age (which is a variable with automatic storage), and it can no longer be accessed to the pointer returned by malloc, resulting in a memory leak (caught by valgrind).
Later in this line:
free (t.age);
free can only free memory for pointers returned by malloc or family, so when used with t.age
exhibits undefined behavior. In this case, free displays an error message and terminates the program, but anything could happen.
If you want to initialize the pointer that malloc returns with the variable _age, you should dereference (*_test).age
and assign it _age, like this:
// NO, sobrescribe `(*_test).age` con un puntero a _age
(*_test).age = &_age;
// SI, desreferencia `(*_test).age` y le asigna _age
*((*_test).age) = _age;