I'm trying to track down where valgrind is finding this invalid write of size 8 in some code, but am having a hard time seeing it. I'm sure valgrind is correct, I just don't see it. I've reproduced the original error by stripping out the function and doing the same thing, more or less, with the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
double* do_realloc(double* orig_graph, int graph_width, int* graph_allocated)
{
double *graph = (double *)(realloc(orig_graph, (graph_width + 1) * sizeof(*graph)));
printf("reallocing graph from %d to %d\n", *graph_allocated, graph_width);
if (!orig_graph) {
/* initialize */
memset(graph, 0, graph_width * sizeof(double));
} else if (graph) {
if (graph_width > *graph_allocated) {
/* initialize the new region */
printf("old region: %p, new region: %p, offset: %d, length: %d\n", orig_graph, graph,
(*graph_allocated * sizeof(double)),
(graph_width - *graph_allocated) * sizeof(*graph));
memset(graph + (*graph_allocated * sizeof(*graph)),
0,
(graph_width - *graph_allocated) * sizeof(*graph));
}
} else {
printf("reallocing FAILED\n");
graph = orig_graph;
graph_width = *graph_allocated;
}
*graph_allocated = graph_width;
return graph;
}
int main()
{
double* graph = NULL;
int allocated = 0;
graph = do_realloc(graph, 307, &allocated);
graph = do_realloc(graph, 300, &allocated);
graph = do_realloc(graph, 307, &allocated);
}
And the valgrind output is:
$ valgrind ./t
==4250== Memcheck, a memory error detector
==4250== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4250== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4250== Command: ./t
==4250==
reallocing graph from 0 to 307
reallocing graph from 307 to 300
reallocing graph from 300 to 307
old region: 0x51d4e60, new region: 0x51d5800, offset: 2400, length: 56
==4250== Invalid write of size 8
==4250== at 0x4C348BE: memset (vg_replace_strmem.c:1094)
==4250== by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250== by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250== Address 0x51da300 is 16,672 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250==
==4250== Invalid write of size 8
==4250== at 0x4C348E6: memset (vg_replace_strmem.c:1094)
==4250== by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250== by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250== Address 0x51da320 is 16,704 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250==
==4250== Invalid write of size 8
==4250== at 0x4C348F3: memset (vg_replace_strmem.c:1094)
==4250== by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250== by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250== Address 0x51da328 is 16,712 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250==
==4250== Invalid write of size 8
==4250== at 0x4C348FD: memset (vg_replace_strmem.c:1094)
==4250== by 0x4007A9: do_realloc(double*, int, int&) (in /home/dmcbride/tmp/v/t)
==4250== by 0x400842: main (in /home/dmcbride/tmp/v/t)
==4250== Address 0x51da330 is 16,720 bytes inside an unallocated block of size 4,185,600 in arena "client"
==4250==
==4250==
==4250== HEAP SUMMARY:
==4250== in use at exit: 2,456 bytes in 1 blocks
==4250== total heap usage: 4 allocs, 3 frees, 8,336 bytes allocated
==4250==
==4250== LEAK SUMMARY:
==4250== definitely lost: 2,456 bytes in 1 blocks
==4250== indirectly lost: 0 bytes in 0 blocks
==4250== possibly lost: 0 bytes in 0 blocks
==4250== still reachable: 0 bytes in 0 blocks
==4250== suppressed: 0 bytes in 0 blocks
==4250== Rerun with --leak-check=full to see details of leaked memory
==4250==
==4250== For counts of detected and suppressed errors, rerun with: -v
==4250== ERROR SUMMARY: 7 errors from 4 contexts (suppressed: 0 from 0)
The original code has much more than this, but I'm only trying to solve the first problem right now, and will continue investigating other problems after this. I think this is related to the crash that the main application is having right after this point, every single time.
(Someone removed the "C" tag because I had left some C++-isms in, but that seems to me to be missing the purpose, so I removed all C++-isms and got the same results.)
from my analysis of the posted code,
The problem is in the call to memset() (which goes along with most of the valgrind error messages.)
Where writing a sizeof(double) beyond the end of the allocated memory area.
And failing to pass the allocated memory to free() before exiting the program.
Related
The following program:
#include <stdlib.h>
int main(void)
{
char *my_str = malloc(42 * sizeof(char));
return 0;
}
Compiled as such:
gcc -g -o prog prog.c
And executed with Valgrind as such:
valgrind --leak-check=full ./prog
Produces the following (truncated) output:
...
==18424== HEAP SUMMARY:
==18424== in use at exit: 42 bytes in 1 blocks
==18424== total heap usage: 1 allocs, 0 frees, 42 bytes allocated
==18424==
==18424== 42 bytes in 1 blocks are definitely lost in loss record 1 of 1
==18424== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18424== by 0x10865B: main (main.c:5)
==18424==
==18424== LEAK SUMMARY:
==18424== definitely lost: 42 bytes in 1 blocks
==18424== indirectly lost: 0 bytes in 0 blocks
==18424== possibly lost: 0 bytes in 0 blocks
==18424== still reachable: 0 bytes in 0 blocks
==18424== suppressed: 0 bytes in 0 blocks
...
Why does Valgrind say that the unfreed memory is "definitely lost"?
From the Valgrind Memcheck docs:
This means that no pointer to the block can be found. The block is classified as "lost", because the programmer could not possibly have freed it at program exit, since no pointer to it exists. This is likely a symptom of having lost the pointer at some earlier point in the program.
However, it's pretty clear that I could have easily freed the block before program exit. What am I missing here? Shouldn't the memory be "still reachable"?
Here's an example of "definitely lost" vs. "still reachable":
#include <stdio.h>
#include <stdlib.h>
void *p;
int main()
{
p = malloc(10);
p = malloc(100);
void *m = malloc(50);
return 0;
}
What happens in this code is the following:
10 bytes are allocated and the pointer to this memory is assigned to the global p.
100 bytes are allocated and the pointer to this memory is assigned to the global p. This overwrites the pointer value that pointed to 10 allocated bytes, and there is no other reference to it. So that memory is "definitely lost".
50 bytes are allocated and the pointer to this memory is assigned to the local m.
main returns causing the lifetime of m to end. As a result there is no reference stored to the memory pointer to 50 bytes so that memory is "definitely lost".
The pointer value pointing to 100 bytes still lives in the global p, so cleanup routines such as those called by atexit or other compiler specific methods could still clean up that memory. So it is "still reachable".
When running valgrind on this code, it outputs the following:
==60822== Memcheck, a memory error detector
==60822== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==60822== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==60822== Command: ./x1
==60822==
==60822==
==60822== HEAP SUMMARY:
==60822== in use at exit: 160 bytes in 3 blocks
==60822== total heap usage: 3 allocs, 0 frees, 160 bytes allocated
==60822==
==60822== LEAK SUMMARY:
==60822== definitely lost: 60 bytes in 2 blocks
==60822== indirectly lost: 0 bytes in 0 blocks
==60822== possibly lost: 0 bytes in 0 blocks
==60822== still reachable: 100 bytes in 1 blocks
==60822== suppressed: 0 bytes in 0 blocks
==60822== Rerun with --leak-check=full to see details of leaked memory
==60822==
==60822== For counts of detected and suppressed errors, rerun with: -v
==60822== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Which is consistent with the description above.
So to summarize, memory is "still reachable" if a pointer to it is stored either in a file scope variable or is pointed to by any "still reachable" memory. Otherwise it is lost.
Why does Valgrind say that the unfreed memory is "definitely lost"?
Because - once main returns the variable my_str doesn't exist anymore. Consequently, there is no way to free the allocated memory. And there is no way to reach the memory. No one know where the memory is. It's lost.
Note: All modern OS systems will however take care of the memory clean up so it's not a real problem.
Valgrind is checking for memory leaks, and you are leaking memory as you didn't free the pointer before exit. You should free(my_str) .
int main(void)
{
char *my_str = malloc(42 * sizeof(char));
free (my_str);
return 0;
}
Definitely Lost mean that nobody has a reference to that memory location anymore, so nobody could free that memory. In a context of a running program that will be a segment of memory that nobody could reuse (so it is lost). Of course at the end of the program nobody will ever use it again, but some of the memory could be referenced by another leaking object (and will be an indirect lost), so with those hints you can debug your program. The link bellow shows a discussion on the topic.
This is a complete response on why you should free memory before exit
Given a struct object with a void pointer (void *) value that is initialized using malloc to hold a string "chapt".
Afterwards, using realloc to make enough memory to concatenate another string.
/* Standard Imports */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct generic_type
{
void *value;
void (*add)(struct generic_type, int);
};
/* Function Declarations */
static void TestRun();
static void AddNumToString(struct generic_type element, int num);
#define TEST_ARRAY_SIZE 1
int main(int argc, char *argv[])
{
TestRun();
(void) argc;
(void) *argv;
return 0;
}
static void TestRun()
{
struct generic_type element;
element.value = malloc(sizeof(char) * 6);
assert (NULL != element.value);
element.value = strcpy(element.value, "chapt");
element.add = AddNumToString;
element.add(element, 10);
free(element.value);
}
static void AddNumToString(struct generic_type element, int num)
{
size_t num_length = snprintf(NULL, 0, "%d", num);
size_t str_length = strlen((char *)(element.value));
size_t new_length = str_length + num_length + 1;
char *num_string = (char *)malloc(sizeof(char) * (num_length + 1));
sprintf(num_string, "%d", num);
element.value = realloc(element.value, sizeof(char) * new_length);
assert (NULL != element.value);
element.value = strcat(((char *)(element.value)), num_string);
free(num_string);
}
This implementation results in the correct output but has a memory leak:
==29031== Memcheck, a memory error detector
==29031== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==29031== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==29031== Command: ./a.out
==29031==
==29031== Invalid free() / delete / delete[] / realloc()
==29031== at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x1088EB: TestRun (teststructs.c:40)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Address 0x522d040 is 0 bytes inside a block of size 6 free'd
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031== Block was alloc'd at
==29031== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x10887B: TestRun (teststructs.c:34)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031==
==29031== HEAP SUMMARY:
==29031== in use at exit: 8 bytes in 1 blocks
==29031== total heap usage: 3 allocs, 3 frees, 17 bytes allocated
==29031==
==29031== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==29031== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==29031== by 0x108999: AddNumToString (teststructs.c:52)
==29031== by 0x1088DF: TestRun (teststructs.c:39)
==29031== by 0x108862: main (teststructs.c:22)
==29031==
==29031== LEAK SUMMARY:
==29031== definitely lost: 8 bytes in 1 blocks
==29031== indirectly lost: 0 bytes in 0 blocks
==29031== possibly lost: 0 bytes in 0 blocks
==29031== still reachable: 0 bytes in 0 blocks
==29031== suppressed: 0 bytes in 0 blocks
==29031==
==29031== For counts of detected and suppressed errors, rerun with: -v
==29031== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
It seems like the problem lies with the realloc line but I can't seem to see the problem with it.
Allocating enough memory during the initialization and avoiding realloc solves the problem but I rather know why this isn't working at this point.
AddNumToString is passed its element argument by value, so that it gets a copy of the object that was passed to it. This means that when you do
element.value = realloc(element.value, sizeof(char) * new_length);
the original pointer contained in the element is freed, but the new one is stored in the copy. The copy is lost when AddNumToString returns, so the newly allocated space is leaked. And worse, the object in the caller remains unchanged; in particular, it still contains the original pointer which has now been freed. So when it's eventually freed (not shown in your current code), that's a double free, which is bad.
You probably want to have AddNumToString take a pointer to struct generic_type instead, so that it can actually modify the object in place.
I am trying to implement the function int *cpy_array(int v[], int size), which copies the array in another and returns the new array as pointer. I also have to watch out for error cases and use dynamic memory.
Ok i know that malloc returns 0 when there is nout enough memory available. I was wondering if there might be any other possible errors as well which I missed out. Then I have to implement free() in the case of succsess as well as in error case.
I tried to implement something like:
if (!w[i]) {
for (k = 0; k < i; ++k)
free(w[k]);
return 0;
}
But there was always an error with this.
In file included from hot.c:2:
C:/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/i686-w64-mingw32/include/stdlib.h:502:27: note: expected 'void *' but argument is of type 'int'"
void __cdecl free(void *_Memory);
And I am not sure why to free() the new array or should the old array be freed? I tried to free it with pointer in my function, but didnt work either and dont think it should be in the main?
Here is the original code:
int *cpy_array(int v[], int size);
int main(void)
{
int size;
size = 4;
int myArray[4] = {1234};
if (*cpy_array(myArray, size) == 0)
{
printf("No memory available.");
}else{
printf("The new Array: %i", *cpy_array(myArray, size));
}
return 0;
}
int *cpy_array(int v[], int size)
{
int i;
int *a = malloc(size * sizeof(int));
if(*a == 0)
return 0;
for (i = 0; i < size; i++)
{
a[i] = v[i];
}
return a;
}
In your first code snippet, you incorrectly deallocated the array of integers w. You can't free single integers in that array, but what you need to do is simply type in:
free(w);
That will free the entire array.
You can also see from the text of the error - note: expected 'void *' but argument is of type 'int'" void __cdecl free(void *_Memory), that the program expected a pointer to the array and not an integer.
You can't free the old array, because it's statically created and the memory for it allocated at the start of the program and it will be freed at the end of the function in which it was defined by the program itself, so you don't need to worry about that. Whereas it's your job to free the dynamically created arrays such as the one you created through the cpy_array(int v[], int size) function.
More on the difference between static and dynamic allocation, you can look up here:
Difference between static memory allocation and dynamic memory allocation
This part of code, wouldn't proparly print the array (you will just print the first number of the array), and also you are calling the function twice, which is excessive and should be done only once for the same array.
if (*cpy_array(myArray, size) == 0)
{
printf("No memory available.");
}else{
printf("The new Array: %i", *cpy_array(myArray, size));
}
You could easify fix these problems by defining a pointer which could store the return value of the function, so you don't have to call it twice and then to correctly print the array use a for loop:
int * copiedArray = cpy_array(myArray, size);
if (copiedArray == NULL)
{
printf("No memory available.");
}else{
printf("The new Array: ");
for (int i = 0; i < size; i++)
printf("%i ", copiedArray[i]);
}
I noticed that you are checking whether a pointer is pointing to something or not incorrectly. Once in main:
if (*cpy_array(myArray, size) == 0)
And once in the cpy_array(int v[], int size) function:
if(*a == 0)
This will not work because you are dereferencing the pointer and checking whether the value to which it is pointing is zero. What you want to do is check the value of the pointer itself. If that is NULL then the allocation didn't work:
if (cpy_array(myArray, size) == NULL)
and
if(a == NULL)
You should use NULL instead of zero because you are explicitly stating that you are checking a value of a pointer, and NULL may not be equal to zero on every machine.
More on that topic here:
What is the difference between NULL, '\0' and 0
To detect you problems concerning the memory use valgrind, If I do that gives :
==10947== Memcheck, a memory error detector
==10947== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10947== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10947== Command: ./a.out
==10947==
==10947== Conditional jump or move depends on uninitialised value(s)
==10947== at 0x10548: cpy_array (c.c:25)
==10947== by 0x104B3: main (c.c:11)
==10947==
==10947== Invalid read of size 4
==10947== at 0x104B8: main (c.c:11)
==10947== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==10947==
==10947==
==10947== Process terminating with default action of signal 11 (SIGSEGV)
==10947== Access not within mapped region at address 0x0
==10947== at 0x104B8: main (c.c:11)
==10947== If you believe this happened as a result of a stack
==10947== overflow in your program's main thread (unlikely but
==10947== possible), you can try to increase the size of the
==10947== main thread stack using the --main-stacksize= flag.
==10947== The main thread stack size used in this run was 8388608.
==10947==
==10947== HEAP SUMMARY:
==10947== in use at exit: 16 bytes in 1 blocks
==10947== total heap usage: 1 allocs, 0 frees, 16 bytes allocated
==10947==
==10947== 16 bytes in 1 blocks are definitely lost in loss record 1 of 1
==10947== at 0x4847568: malloc (vg_replace_malloc.c:299)
==10947== by 0x10533: cpy_array (c.c:24)
==10947== by 0x104B3: main (c.c:11)
==10947==
==10947== LEAK SUMMARY:
==10947== definitely lost: 16 bytes in 1 blocks
==10947== indirectly lost: 0 bytes in 0 blocks
==10947== possibly lost: 0 bytes in 0 blocks
==10947== still reachable: 0 bytes in 0 blocks
==10947== suppressed: 0 bytes in 0 blocks
==10947==
==10947== For counts of detected and suppressed errors, rerun with: -v
==10947== Use --track-origins=yes to see where uninitialised values come from
==10947== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 6 from 3)
The "Conditional jump or move depends on uninitialised value(s)" comes from the *a in if(*a == 0) and "Invalid read of size 4 ..." because you dereference 0 because of the return 0;
after changing if(*a == 0) to if(a == 0) to solve the two previous problems that condition is (a priori) false and _valgrind says :
==11116== Memcheck, a memory error detector
==11116== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11116== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11116== Command: ./a.out
==11116==
Mein neuer Array enthaelt folgende Zeichen: 1==11116==
==11116== HEAP SUMMARY:
==11116== in use at exit: 32 bytes in 2 blocks
==11116== total heap usage: 3 allocs, 1 frees, 1,056 bytes allocated
==11116==
==11116== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==11116== at 0x4847568: malloc (vg_replace_malloc.c:299)
==11116== by 0x10523: cpy_array (c.c:24)
==11116== by 0x104A3: main (c.c:11)
==11116==
==11116== 16 bytes in 1 blocks are definitely lost in loss record 2 of 2
==11116== at 0x4847568: malloc (vg_replace_malloc.c:299)
==11116== by 0x10523: cpy_array (c.c:24)
==11116== by 0x104CF: main (c.c:15)
==11116==
==11116== LEAK SUMMARY:
==11116== definitely lost: 32 bytes in 2 blocks
==11116== indirectly lost: 0 bytes in 0 blocks
==11116== possibly lost: 0 bytes in 0 blocks
==11116== still reachable: 0 bytes in 0 blocks
==11116== suppressed: 0 bytes in 0 blocks
==11116==
==11116== For counts of detected and suppressed errors, rerun with: -v
==11116== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 3)
so yes you have memory leaks because you lost 2 times the allocation return by cpy_array
you need to have something like :
int * v = cpy_array(myArray, size);
if (*v == 0)
{
printf("Speicher kann nicht freigegeben werden.");
}else{
printf("Mein neuer Array enthaelt folgende Zeichen: %i",
*v);
}
free(v);
Doing that correction valgrind signals nothing :
valgrind --leak-check=full ./a.out
==11224== Memcheck, a memory error detector
==11224== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==11224== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==11224== Command: ./a.out
==11224==
Mein neuer Array enthaelt folgende Zeichen: 1==11224==
==11224== HEAP SUMMARY:
==11224== in use at exit: 0 bytes in 0 blocks
==11224== total heap usage: 2 allocs, 2 frees, 1,040 bytes allocated
==11224==
==11224== All heap blocks were freed -- no leaks are possible
==11224==
==11224== For counts of detected and suppressed errors, rerun with: -v
==11224== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
I encourage you to
compile with all warning detection, like gcc -g -Wall -pedantic ...
when you have problem use valgrind and/or debugger
even you do not see a problem run anyway under valgrind, so problems can be hidden
this is not the correct way to initialize the array
int myArray[4] = {1234};
write
int myArray[4] = { 1,2,3,4 };
or simply
int myArray[] = { 1,2,3,4 };
Calling the function cpy_array .. when you write
if (*cpy_array(myArray, size) == 0)
Is not correct, why? because what if the function returns NULL, then you are dereferencing NULL
In your function cpy_array you are dereferencing a, that is not correct, instead compare the pointer
if ( a == NULL)
and use the standard constant NULL for a null pointer instead of 0 since it may not be 0 on all platforms.
I'm trying to backfill my knowledge of C memory management. I've come from a mostly scripting and managed background, and I want to learn more about C and C++. To that end I've been reading a few books, including one which included this example of using realloc to trim a string of whitespace:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* trim(char* phrase)
{
char* old = phrase;
char* new = phrase;
while(*old == ' ') {
old++;
}
while(*old) {
*(new++) = *(old++);
}
*new = 0;
return (char*)realloc(phrase, strlen(phrase)+1);
}
int main ()
{
char* buffer = (char*)malloc(strlen(" cat")+1);
strcpy(buffer, " cat");
printf("%s\n", trim(buffer));
free(buffer);
buffer=NULL;
return 0;
}
I dutifully copied the example, and compiled with c99 -Wall -Wpointer-arith -O3 -pedantic -march=native. I don't get any compile errors, and the app runs and does what's promised in the book, but when I run it against valgrind I get an error about invalid realloc.
==21601== Memcheck, a memory error detector
==21601== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21601== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==21601== Command: ./trim
==21601==
==21601== Invalid free() / delete / delete[] / realloc()
==21601== at 0x402B3D8: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==21601== by 0x804844E: main (in /home/mo/programming/learning_pointers/trim)
==21601== Address 0x4202028 is 0 bytes inside a block of size 6 free'd
==21601== at 0x402C324: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==21601== by 0x80485A9: trim (in /home/mo/programming/learning_pointers/trim)
==21601== by 0x804842E: main (in /home/mo/programming/learning_pointers/trim)
==21601==
==21601==
==21601== HEAP SUMMARY:
==21601== in use at exit: 4 bytes in 1 blocks
==21601== total heap usage: 2 allocs, 2 frees, 10 bytes allocated
==21601==
==21601== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==21601== at 0x402C324: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==21601== by 0x80485A9: trim (in /home/mo/programming/learning_pointers/trim)
==21601== by 0x804842E: main (in /home/mo/programming/learning_pointers/trim)
==21601==
==21601== LEAK SUMMARY:
==21601== definitely lost: 4 bytes in 1 blocks
==21601== indirectly lost: 0 bytes in 0 blocks
==21601== possibly lost: 0 bytes in 0 blocks
==21601== still reachable: 0 bytes in 0 blocks
==21601== suppressed: 0 bytes in 0 blocks
==21601==
==21601== For counts of detected and suppressed errors, rerun with: -v
==21601== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
So please help me understand why it's consider an invalid realloc. Is the example crap? Is there something I'm missing? I know that according to the specs, realloc expects the pointer to have been created previously by malloc, so is it because the realloc is in another function? Or is valgrind confused because they're in separate functions? I'm not a complete idiot (most days), but right now I kind of feel like one for not seeing the issue.
Thanks in advance!
You're trying to free the original pointer, not the reallocd one. You can fix it by:
buffer = trim(buffer)
I have the following C code:
static void* heap;
static unsigned int ptr;
int main(void) {
...
heap=(void*)malloc(10000*sizeof(char));
ptr=&heap;
/*Actual sniffing*/
pcap_loop(handle,-1,callback,NULL);
return 0;
}
And here is the callback function that gets called every once in a while:
void callback(u_char *useless,const struct pcap_pkthdr* header,const u_char* packet){
const u_char *payload;
...
payload = (u_char *)(packet + size_ethernet + size_ip + size_tcp);
unsigned int hash=DJBHash(payload,strlen(payload));
printf("%u\n",hash); //ok
int len=strlen(payload)*sizeof(u_char);
printf("len:%d, ptr:%d\n",len,ptr); //ok
memcpy(ptr,(char)payload,len*sizeof(u_char)); //I'm getting a seg fault here!
ptr+=len;
}
Here is my dump from valgrind:
==8687== Memcheck, a memory error detector
==8687== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==8687== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==8687== Command: ./ByteCache
==8687==
==8687== Syscall param socketcall.setsockopt(optval) points to uninitialised byte(s)
==8687== at 0x514D12A: setsockopt (syscall-template.S:82)
==8687== by 0x4E34991: ??? (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x4E34AB2: ??? (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x401A3F: main (ByteCache.c:123)
==8687== Address 0x7fefffb42 is on thread 1's stack
==8687==
2912431451
len:12, ptr:6304012
==8687== Invalid read of size 8
==8687== at 0x4C2A337: memcpy (mc_replace_strmem.c:635)
==8687== by 0x4018CB: callback (ByteCache.c:77)
==8687== by 0x4E34E24: ??? (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x4E3A818: pcap_loop (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x401AB4: main (ByteCache.c:133)
==8687== Address 0x80 is not stack'd, malloc'd or (recently) free'd
==8687==
==8687==
==8687== Process terminating with default action of signal 11 (SIGSEGV)
==8687== Access not within mapped region at address 0x80
==8687== at 0x4C2A337: memcpy (mc_replace_strmem.c:635)
==8687== by 0x4018CB: callback (ByteCache.c:77)
==8687== by 0x4E34E24: ??? (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x4E3A818: pcap_loop (in /usr/lib/libpcap.so.1.1.1)
==8687== by 0x401AB4: main (ByteCache.c:133)
==8687== If you believe this happened as a result of a stack
==8687== overflow in your program's main thread (unlikely but
==8687== possible), you can try to increase the size of the
==8687== main thread stack using the --main-stacksize= flag.
==8687== The main thread stack size used in this run was 8388608.
==8687==
==8687== HEAP SUMMARY:
==8687== in use at exit: 22,711 bytes in 11 blocks
==8687== total heap usage: 41 allocs, 30 frees, 38,352 bytes allocated
==8687==
==8687== LEAK SUMMARY:
==8687== definitely lost: 0 bytes in 0 blocks
==8687== indirectly lost: 0 bytes in 0 blocks
==8687== possibly lost: 0 bytes in 0 blocks
==8687== still reachable: 22,711 bytes in 11 blocks
==8687== suppressed: 0 bytes in 0 blocks
==8687== Reachable blocks (those to which a pointer was found) are not shown.
==8687== To see them, rerun with: --leak-check=full --show-reachable=yes
==8687==
==8687== For counts of detected and suppressed errors, rerun with: -v
==8687== Use --track-origins=yes to see where uninitialised values come from
==8687== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)
Segmentation fault
Unfortunately, I can't seem to make much sense of it.
Any insight greatly appreciated.
Many thanks in advance,
Thanks to Kerrick SB, I've gotten one step further.
Here now is the output:
eamorr#Compaq6000:/mnt/eamorr/workspace/ByteCache/Debug# ./ByteCache
361457034
len:872, ptr:6304000
46267872
len:12, ptr:-92779411
Segmentation fault
I can see a negative ptr? I have no idea how this is possible. I've even changed ptr to type unsigned int.
I don't think you want to do ptr = &heap, you want ptr = heap. malloc returns a pointer to the memory it allocated, which seems to be what you're trying to refer to in your callback.
You only want to use the & to get the address of something. For example:
MyStructure MyVariable;
void* pAPointer = &MyVariable;
If you're malloc-ing you get a pointer returned so:
MyStructure *pPointerToStructure = malloc(sizeof(MyStructure));
to use the & on pPointerToStructure gives you the pointer to the pointer, not to the allocated memory from the malloc call
memcpy takes void pointers as its arguments, yet you're casting the second argument to a char. To fix this:
memcpy(ptr, (const void *) payload, len * sizeof(u_char));
For that matter, why don't you declare ptr as void** (i.e. say static void ** ptr;)?
Also, why all the excessive casting? You don't need to cast the result of malloc() or of the payload = assignment, as they're already the correct type. Finally, len should probably be of type size_t, because it's a size type (i.e. unsigned).