Reputation: 35
I've been experimenting with dynamic memory allocation and I've come across the munmap_chunk error in C. Here's my code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_input(char **input) {
*input = (char *) malloc (100);
*input = "hello world";
}
int main() {
char *input;
get_input(&input);
puts(input);
free(input);
return 0;
}
Here's what valgrind showed when the program is executed.
==4116== Memcheck, a memory error detector
==4116== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4116== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4116== Command: ./a.out
==4116==
hello world
==4116== Invalid free() / delete / delete[] / realloc()
==4116== at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4116== by 0x400615: main (in /home/mark/Documents/CS32/a.out)
==4116== Address 0x4006a4 is not stack'd, malloc'd or (recently) free'd
==4116==
==4116==
==4116== HEAP SUMMARY:
==4116== in use at exit: 100 bytes in 1 blocks
==4116== total heap usage: 1 allocs, 1 frees, 100 bytes allocated
==4116==
==4116== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==4116== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4116== by 0x4005D2: get_input (in /home/mark/Documents/CS32/a.out)
==4116== by 0x4005FD: main (in /home/mark/Documents/CS32/a.out)
==4116==
==4116== LEAK SUMMARY:
==4116== definitely lost: 100 bytes in 1 blocks
==4116== indirectly lost: 0 bytes in 0 blocks
==4116== possibly lost: 0 bytes in 0 blocks
==4116== still reachable: 0 bytes in 0 blocks
==4116== suppressed: 0 bytes in 0 blocks
==4116==
==4116== For counts of detected and suppressed errors, rerun with: -v
==4116== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Why does the free() function behave like this? Also, from the valgrind log, why does my char *input variable not being allocated by malloc()?
Upvotes: 1
Views: 1064
Reputation: 26121
The problem is this line just after malloc
. (BTW don't cast malloc return.)
*input = "hello world";
What happen? "hello world"
tells the compiler to make some data space in, let's call it data segment, and insert bytes representing the string "hello world"
including terminating '\0'
there. Then generate the code which inserts the pointer pointing this string into place where input
points. It means you made previous line code useless. Just imagine these two assignments one after one x = 1; x = 2;
. It's what you just done, but x
is *input
.
Then the story continues, you return from get_input()
and end up with this pointer to the string in variable input
in main
function scope. Then you feed it into free()
call. But it is not pointer returned by malloc()
. You lost it.
If you would like to have "hello world" in input you can either do
void get_input(char **input) {
*input = (char *) malloc (100);
strcpy(*input, "hello world");
}
int main() {
char *input;
get_input(&input);
puts(input);
free(input);
return 0;
}
or
void get_input(char **input) {
*input = "hello world";
}
int main() {
char *input;
get_input(&input);
puts(input);
return 0;
}
but now you should be careful what you do with data pointed by input
because it points to some part of memory you can't modify, free()
or realloc()
.
Upvotes: 0
Reputation: 41017
You can assign in this way:
*input = "hello world"; /* Not modifiable */
But then, you don't need to reserve space with malloc
, "hello world"
has his own address (at some "read only" segment) and any attempt to modify the string results in undefined behavior, so you are not allowed to free
it.
If you want a modifiable string:
void get_input(char **input) {
char str[] = "hello world";
*input = malloc(sizeof(str)); /* Don't cast malloc */
if (*input == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
strncpy(*input, str, sizeof(str));
}
or
void get_input(char **input) {
*input = strdup("hello world");
}
Note that strdup
is not standard but it's available on many implementations.
Upvotes: 1