CS50 week 4, "Recover problem", issue with memory leak - c

your textI actually, after a lot of sweating, finished the "recover" problem of the cs50 course. The last error I was getting was a memory leak and although I fixed it I still do not understand why I was getting it. So I would be glad if somebody could explain it to me.
The line that give me the error is the one below( BYTE is a typedef they suggested to create in the problem's specification, I created it like this: typedef uint8_t BYTE; and I used it somewhere else in the code without problems)
//Allocating space for images names
char *filename = malloc(1 *(sizeof(BYTE)));
And this is what valgrind says:
==2963== Memcheck, a memory error detector
==2963== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2963== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2963== Command: ./recover card.raw
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x4A09822: \_IO_padn (iopadn.c:64)
==2963== by 0x49FF817: pad_func (vfprintf-internal.c:196)
==2963== by 0x49FF817: \__vfprintf_internal (vfprintf-internal.c:1516)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x49FED28: outstring_func (vfprintf-internal.c:239)
==2963== by 0x49FED28: \__vfprintf_internal (vfprintf-internal.c:1516)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== Address 0x4bb5262 is 1 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A17034: \_IO_default_xsputn (genops.c:394)
==2963== by 0x4A17034: \_IO_default_xsputn (genops.c:370)
==2963== by 0x49FF049: outstring_func (vfprintf-internal.c:239)
==2963== by 0x49FF049: \__vfprintf_internal (vfprintf-internal.c:1593)
==2963== by 0x4A0AA08: \__vsprintf_internal (iovsprintf.c:95)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
=2963== Address 0x4bb5263 is 2 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Invalid write of size 1
==2963== at 0x4A0AA0E: \__vsprintf_internal (iovsprintf.c:97)
==2963== by 0x49E99A7: sprintf (sprintf.c:30)
==2963== by 0x1092FD: main (recover.c:52)
==2963== Address 0x4bb5267 is 6 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963== Syscall param openat(filename) points to unaddressable byte(s)
==2963== at 0x4A9D6EB: open (open64.c:41)
==2963== by 0x4A15135: \_IO_file_open (fileops.c:188)
==2963== by 0x4A15491: \_IO_file_fopen##GLIBC_2.2.5 (fileops.c:280)
==2963== by 0x4A0872D: \__fopen_internal (iofopen.c:75)
==2963== by 0x4A0872D: fopen##GLIBC_2.2.5 (iofopen.c:86)
==2963== by 0x109316: main (recover.c:56)
==2963== Address 0x4bb5261 is 0 bytes after a block of size 1 alloc'd
==2963== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==2963== by 0x109241: main (recover.c:29)
==2963==
==2963==
==2963== HEAP SUMMARY:
==2963== in use at exit: 0 bytes in 0 blocks
==2963== total heap usage: 104 allocs, 104 frees, 233,481 bytes allocated
==2963==
==2963== All heap blocks were freed -- no leaks are possible
==2963==
==2963== For lists of detected and suppressed errors, rerun with: -s
==2963== ERROR SUMMARY: 400 errors from 5 contexts (suppressed: 0 from 0)
And these are the check50 results:
:) recover.c exists.
:) recover.c compiles.
:) handles lack of forensic image
:) recovers 000.jpg correctly
:) recovers middle images correctly
:) recovers 049.jpg correctly
:( program is free of memory errors
valgrind tests failed; see log for more information.
But if a change the error line in:
//Allocating space for images names
char *filename = malloc(8 *(sizeof(char)));
everything works fine. The space allocated is 1 byte in both case and it is freed in both cases, why do I get an error if I use the typedef BYTE?

//Allocating space for images names
char *filename = malloc(1 *(sizeof(BYTE)));
BYTE is aliasing uint8_t, which is an (at least) 8-bit unsigned type, which itself is aliasing an unsigned char. This allocates memory for just 1 char/ byte. Assuming it's a string, it can only ever hold the null-byte.
//Allocating space for images names
char *filename = malloc(8 *(sizeof(char)));
The space allocated is 1 byte in both case.
No, the space allocated is 8 bytes here (sizeof (char) is by definition 1), which is large enough to hold 000.jpg + \0. But you do not require malloc() here. The size of the allocation is known at compile time and remains constant, so it'd better to just use a plain array[8] of char.
I used it somewhere else in the code without problems.
You got lucky. It's undefined behaviour to reference out of bounds memory (and that includes reading and writing).
Permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of a
diagnostic message).
The OS gives out memory in pages (usually 4k or so). If you ask malloc() for one byte, it might allocate a pagesize worth of memory instead (if the call to malloc() doesn't get optimized or it's out of memory). malloc() then organizes the page into chunks, do some book keeping, ensures the memory is suitably-aligned for any built-in type, and more. Writing past the end of the chunk may stay on the same page, and as far as the OS is concerned, you didn't access any illegal memory address. So your program might appear to work just fine until you go too far, and it segfaults, or erase your harddrive, or launch a missile (assuming you have the correct hardware installed), or worse, make demons fly out of your nose..
Remember the adage:
"Anything that can go wrong will go wrong, and at the worst possible time."

Related

How do I allocate memory for a textstring from the terminal?

So I have a struct where I have my char array, it looks like this,
typedef struct data_{
char * path;
} data;
I want to be able to type a huge string in the terminal and save the string in this array, what I have tried now is this,
data * data_ptr = malloc(sizeof(data));
data_ptr->path = malloc(sizeof(argv[i]) + 1); /*+ 1 to allocate an extra bit for I/O*/
strcpy(data->path, argv[i]);
and before I quit the program I free the memory. But I get Segmentation fault for some reason. I have allocated memory on two other places in my code and they seem to work just fine.. I'm kind of new to Valgrind and trying to decode what it is trying to tell me that the problem is but it yells too much for me too comprehend.
==3117== Memcheck, a memory error detector
==3117== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3117== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3117== Command: ./***
==3117==
==3117== Syscall param open(filename) contains uninitialised byte(s)
==3117== at 0x4F30460: __open_nocancel (syscall-template.S:84)
==3117== by 0x4EB3ACD: _IO_file_open (fileops.c:221)
==3117== by 0x4EB3D34: _IO_file_fopen##GLIBC_2.2.5 (fileops.c:328)
==3117== by 0x4EA7D33: __fopen_internal (iofopen.c:86)
==3117== by 0x400AF7: search_file (in /home/***)
==3117== by 0x400BE5: main (in /home/***)
==3117== Uninitialised value was created by a stack allocation
==3117== at 0x400B8C: main (in /home/***)
==3117==
File does not exist.
==3117== Conditional jump or move depends on uninitialised value(s)
==3117== at 0x4C2EDA1: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3117== by 0x400BF1: main (in /home/***)
==3117== Uninitialised value was created by a stack allocation
==3117== at 0x400B8C: main (in /home/***)
==3117==
==3117== Invalid free() / delete / delete[] / realloc()
==3117== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3117== by 0x400BF1: main (in /home/***)
==3117== Address 0x400770 is in the Text segment of /home/***
==3117== at 0x400770: _start (in /home/***)
==3117==
==3117== Conditional jump or move depends on uninitialised value(s)
==3117== at 0x4C2EDA1: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3117== by 0x400BFD: main (in /home/***)
==3117== Uninitialised value was created by a stack allocation
==3117== at 0x400B8C: main (in /home/***)
==3117==
==3117== Invalid free() / delete / delete[] / realloc()
==3117== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3117== by 0x400BFD: main (in /home/***)
==3117== Address 0xffefffeb0 is on thread 1's stack
==3117==
==3117==
==3117== HEAP SUMMARY:
==3117== in use at exit: 24 bytes in 1 blocks
==3117== total heap usage: 3 allocs, 4 frees, 1,600 bytes allocated
==3117==
==3117== 24 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3117== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3117== by 0x400882: parse (in /home/***)
==3117== by 0x400BC6: main (in /home/***)
==3117==
==3117== LEAK SUMMARY:
==3117== definitely lost: 24 bytes in 1 blocks
==3117== indirectly lost: 0 bytes in 0 blocks
==3117== possibly lost: 0 bytes in 0 blocks
==3117== still reachable: 0 bytes in 0 blocks
==3117== suppressed: 0 bytes in 0 blocks
==3117==
==3117== For counts of detected and suppressed errors, rerun with: -v
==3117== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
Is anyone able to see what I may be doing wrong? My take on Valgrinds output is that I try to reach memory that I do not have access to, or that I am messing with the stack in some strange way. But I do not know to be honest.
This:
data_ptr->path = malloc(sizeof(argv[i]) + 1)
is wrong, you can't use sizeof to get the length of a string at runtime like that. You must use strlen():
data_ptr->path = malloc(strlen(argv[i]) + 1);
If you have it, you can use strdup() to do both the allocation and the copying. Saves you from having to remember that + 1.
argv[i] is a pointer to a string, but not the string itself. Therefore when you do sizeof(argv[i]) you only get the size of the pointer and not what it points to.
So when you do malloc(sizeof(argv[i]) + 1) you will only allocate 5 or 9 bytes (depending on the pointers size, typically 4 bytes for 32-bit systems and 8 bytes for 64-bit systems).
You need to use strlen to get the length of the string.
Use strlen(argv[i]) rather than sizeof
data * data_ptr = malloc(sizeof(data));
data_ptr->path = malloc(strlen(argv[i]));
strcpy(data->path, argv[i]);
I hope that the value of i is within the range 0 to argc..
As others have pointed out, you can't use sizeof, you should use strlen when doing the malloc.
But, valgrind is telling you what's wrong, you're trying to open a file that doesn't exist.
==3117== Syscall param open(filename) contains uninitialised byte(s)
==3117== at 0x4F30460: __open_nocancel (syscall-template.S:84)
==3117== by 0x4EB3ACD: _IO_file_open (fileops.c:221)
==3117== by 0x4EB3D34: _IO_file_fopen##GLIBC_2.2.5 (fileops.c:328)
==3117== by 0x4EA7D33: __fopen_internal (iofopen.c:86)
==3117== by 0x400AF7: search_file (in /home/***)
==3117== by 0x400BE5: main (in /home/***)
==3117== Uninitialised value was created by a stack allocation
==3117== at 0x400B8C: main (in /home/***)
==3117==
File does not exist.
So, perhaps you're attempting to open a file that's bogus (i.e. the value of filename is bogus or it's just garbage data)? Or, you're passing bogus data to fopen? What is the path you're passing to fopen?

memory errors while reading a large file in C

I am very novice in working with malloc/realloc in C and so need some help. The following is short snippet of a big program where I intend to read a big (fasta) file almost 80000 line numbers and store the first line marked with > (name) and following line (sequence) in two separate arrays- fasta_name and fasta_seq. I have used a standard library which gives the output as a structure but I need to change it into arrays since later on the program I need to check input provided by the user with each of the fasta entries in the file..
The inputfile format is:
P21306\n
MSAWRKAGISYAAYLNVAAQAIRSSLKTELQTASVLNRSQTDAFYTQYKNGTAASEPTPITK\n
P38077\n
MLSRIVSNNATRSVMCHQAQVGILYKTNPVRTYATLKEVEMRLKSIKNIEKITKTMKIVASTRLSKAEKA\n
=======================
The code is:
KSEQ_INIT(gzFile, gzread) ///EXTERNAL LIBRARY FOR BIOLOGISTS READING FASTA FORMAT FILE///
int main(int argc,char *argv[])
{
char **fasta_name=(char **)malloc(sizeof(char *)*80000);
for(i=0;i<size;i++)
{
fasta_name[i]=(char*)malloc(sizeof(char)*50);
}
char **fasta_seq=(char**)malloc(sizeof(char *)*80000);
for(i=0;i<size;i++)
{
fasta_seq[i]=(char*)malloc(sizeof(char)*5000);
}
fpf = gzopen("fasta_seq_nr_uniprot.txt", "r");
seq = kseq_init(fpf);
while((l = kseq_read(seq)) >= 0)
{
strcpy(fasta_name[index1],seq->name.s);
strcpy(fasta_seq[index1],seq->seq.s);
index1++;
}
kseq_destroy(seq);
gzclose(fpf);
for(i=0;i<size;i++)
{
free(fasta_name[i]);
}
for(i=0;i<size;i++)
{
free(fasta_seq[i]);
}
free(fasta_name);
free(fasta_seq);
The program shows no compilation errors but the following memory errors and segmentation fault using Valgrind.
$ valgrind --track-origins=yes --leak-check=full ./Gwidd_uniprot_map2 xaa==3511== Memcheck, a memory error detector
==3511== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==3511== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==3511== Command: ./map2 xaa
==3511==
--3511-- ./map2:
--3511-- dSYM directory has wrong UUID; consider using --dsymutil=yes
Opening file xaa
==3511== Use of uninitialised value of size 8
==3511== at 0x100012C43: __strcpy_chk (mc_replace_strmem.c:893)
==3511== by 0x100001A78: __inline_strcpy_chk (in ./map2)
==3511== by 0x10000183E: main (in ./map2)
==3511== Uninitialised value was created by a heap allocation
==3511== at 0x100011345: malloc (vg_replace_malloc.c:236)
==3511== by 0x10000170C: main (in ./map2)
==3511==
==3511== Invalid write of size 1
==3511== at 0x100012C43: __strcpy_chk (mc_replace_strmem.c:893)
==3511== by 0x100001A78: __inline_strcpy_chk (in ./map2)
==3511== by 0x10000183E: main (in ./map2)
==3511== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==3511==
==3511==
==3511== Process terminating with default action of signal 11 (SIGSEGV)
==3511== Access not within mapped region at address 0x0
==3511== at 0x100012C43: __strcpy_chk (mc_replace_strmem.c:893)
==3511== by 0x100001A78: __inline_strcpy_chk (in ./map2)
==3511== by 0x10000183E: main (in ./map2)
==3511== If you believe this happened as a result of a stack
==3511== overflow in your program's main thread (unlikely but
==3511== possible), you can try to increase the size of the
==3511== main thread stack using the --main-stacksize= flag.
==3511== The main thread stack size used in this run was 8388608.
==3511==
==3511== HEAP SUMMARY:
==3511== in use at exit: 6,674,813 bytes in 3,664 blocks
==3511== total heap usage: 3,807 allocs, 143 frees, 6,698,108 bytes allocated
==3511==
==3511== LEAK SUMMARY:
==3511== definitely lost: 0 bytes in 0 blocks
==3511== indirectly lost: 0 bytes in 0 blocks
==3511== possibly lost: 0 bytes in 0 blocks
==3511== still reachable: 6,674,813 bytes in 3,664 blocks
==3511== suppressed: 0 bytes in 0 blocks
==3511== Reachable blocks (those to which a pointer was found) are not shown.
==3511== To see them, rerun with: --leak-check=full --show-reachable=yes
==3511==
==3511== For counts of detected and suppressed errors, rerun with: -v
==3511== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault
CODE EDITED AS:
char **fasta_name=(char **)malloc(sizeof(char *)*80000);
if(fasta_name == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
for(i=0;i<size;i++)
{
fasta_name[i]=(char*)malloc(sizeof(char)*50);
if(fasta_name[i] == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
}
char **fasta_seq=(char**)malloc(sizeof(char *)*80000);
if(fasta_seq == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
for(i=0;i<size;i++)
{
fasta_seq[i]=(char*)malloc(sizeof(char)*5000);
if(fasta_seq[i] == NULL)
{
printf("Unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
}
fpf = gzopen("fasta_seq_nr_uniprot.txt", "r");
seq = kseq_init(fpf);
while((l = kseq_read(seq)) >= 0)
{
strcpy(fasta_name[index1],seq->name.s);
strcpy(fasta_seq[index1],seq->seq.s);
index1++;
}
kseq_destroy(seq);
gzclose(fpf);
Based on the error Access not within mapped region at address, I would say that you are accessing memory that's out of bounds, causing your segmentation fault. Check that malloc() doesn't return NULL to you after calling it, otherwise you risk accessing memory you don't actually own.
Do this after every single malloc() call. For example:
int *i = (int *) malloc(sizeof(int));
if(!i){
fprintf(stderr, "Something went wrong with malloc(), exiting...\n");
exit(1);
}
Another thing to check is to see if index1 is out of bounds of your allocations. I don't see where it's declared or initialized. Is it possible that your allocation for fasta_name and others is too small, given that you read information using a while loop that keeps incrementing the index?

invalid read memory - valgrind

Here is my code: I am trying to get the info of an struct and deep copy the info. But, valgrind shows that "invalid read". I know that is I read the memory that is released. I don't know why; is anyone able to figure it out for me?
Code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct student
{
int id;
char *name;
int age;
};
void get_info(struct student *dest, struct student *src)
{
memcpy(dest,src,sizeof(struct student));
dest->name = strdup(src->name);
}
int main()
{
struct student foo;
foo.id = 1001;
foo.name = strdup("kevin");
foo.age = 18;
struct student bar;
get_info(&bar, &foo);
puts(bar.name);
free(foo.name);
free(bar.name);
return 0;
}
Valgrind report
valgrind --tool=memcheck --leak-check=full ./test
==2130== Memcheck, a memory error detector
==2130== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2130== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==2130== Command: ./test
==2130==
==2130== Invalid read of size 4
==2130== at 0x40B083B: ??? (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x40B04A4: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484B1: get_info (test.c:15)
==2130== by 0x80484F8: main (test.c:26)
==2130== Address 0x419902c is 4 bytes inside a block of size 6 alloc'd
==2130== at 0x4026775: malloc (vg_replace_malloc.c:291)
==2130== by 0x40B04AF: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484D8: main (test.c:22)
==2130==
==2130== Invalid read of size 4
==2130== at 0x40B083B: ??? (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x409ACE4: puts (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x8048504: main (test.c:28)
==2130== Address 0x4199064 is 4 bytes inside a block of size 6 alloc'd
==2130== at 0x4026775: malloc (vg_replace_malloc.c:291)
==2130== by 0x40B04AF: strdup (in /lib/tls/i686/cmov/libc-2.11.1.so)
==2130== by 0x80484B1: get_info (test.c:15)
==2130== by 0x80484F8: main (test.c:26)
==2130==
kevin
==2130==
==2130== HEAP SUMMARY:
==2130== in use at exit: 0 bytes in 0 blocks
==2130== total heap usage: 2 allocs, 2 frees, 12 bytes allocated
==2130==
==2130== All heap blocks were freed -- no leaks are possible
==2130==
==2130== For counts of detected and suppressed errors, rerun with: -v
==2130== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 11 from 6)
I think this is actually an error report from valgrind that you should suppress. It is ultimately a bug in the C library on your system.
The complaint is that code called from strdup() is reading 4 bytes at an offset of 4 bytes into a block of 6 bytes that were allocated by malloc(). Given that "kevin" occupies 6 bytes, then I believe a memcpy() variant has been employed by strdup() and has been caught in the act of reading 4 bytes at a time through the data. While it is probably actually safe, technically, valgrind is correct to complain. However, you can't do anything about that — your code is innocent, and the system library is guilty. That's the sort of thing suppressions are for!
+---+---+---+---+---+---+...+...+
| k | e | v | i | n | \0| ? | ? |
+---+---+---+---+---+---+...+...+
The fast copy is using the fact that the malloc()'d data is 4-byte (more likely, 8-byte) aligned. It copies the 4 bytes 'k', 'e', 'v', and 'i' in one operation; it then copies the other two bytes of the string ('n', '\0') plus the two bytes that are not technically part of the allocated space in a second operation. The minimum actual allocation is probably 8 bytes on a 32-bit system; it tends to be 16-bytes on 64-bit machines. That means that the extra two bytes are part of the space reserved for the memory allocation, but valgrind is correct to report that the code is copying outside the allocated space.
This looks like an optimization in strdup() and puts(), they read their input in chunks of four bytes instead of one byte at a time, however they are careful not to write beyond the end. This is safe as long as the four byte addresses are aligned: Properly aligned reads can never trigger a hardware exception, and since these two functions do not write beyond the end of the string, their operation is safe, even though it is illegal from a language point of view. And you can be certain that these four byte addresses will be properly aligned because it's an optimization, unaligned reading would bring the code to crawl.
Valgrind checks on the language level of correctness, not on the physical level, hence the error report. So I agree with Jonathan Leffler that you should just suppress this "error", which, looking at the comments, seems to be automatically done by more recent versions of valgrind.

C: Please help me debug this memory-related seg fault

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).

Malloc, string pointers, and Valgrind

My program is like this (main.c):
#include <stdlib.h>
#include <stdio.h>
void main(){
char *first="hello ";
char *second="world!";
char *seq=(char *)malloc((strlen(first)+1)*sizeof(char));
strcat(strcpy(seq,first),second);
printf("%s\n",seq);
free(seq);
}
and I debug with the tool valgrind, it said that($:valgrind --tool=memcheck --leak-check=full --track-origins=yes ./main):
==5118== Memcheck, a memory error detector.
==5118== Copyright (C) 2002-2008, and GNU GPL'd, by Julian Seward et al.
==5118== Using LibVEX rev 1884, a library for dynamic binary translation.
==5118== Copyright (C) 2004-2008, and GNU GPL'd, by OpenWorks LLP.
==5118== Using valgrind-3.4.1, a dynamic binary instrumentation framework.
==5118== Copyright (C) 2000-2008, and GNU GPL'd, by Julian Seward et al.
==5118== For more details, rerun with: -v
==5118==
==5118== Invalid write of size 1
==5118== at 0x402575B: strcat (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484EB: main (main.c:7)
==5118== Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118== at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484C3: main (main.c:6)
==5118==
==5118== Invalid write of size 1
==5118== at 0x4025777: strcat (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484EB: main (main.c:7)
==5118== Address 0x418a034 is 5 bytes after a block of size 7 alloc'd
==5118== at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484C3: main (main.c:6)
==5118==
==5118== Invalid read of size 1
==5118== at 0x4025963: strlen (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x40A0FA4: puts (in /lib/libc-2.10.1.so)
==5118== by 0x80484F7: main (main.c:8)
==5118== Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118== at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484C3: main (main.c:6)
==5118==
==5118== Invalid read of size 1
==5118== at 0x40ACEFE: _IO_default_xsputn (in /lib/libc-2.10.1.so)
==5118== by 0x40AA3D0: _IO_file_xsputn##GLIBC_2.1 (in /lib/libc-2.10.1.so)
==5118== by 0x40A1020: puts (in /lib/libc-2.10.1.so)
==5118== by 0x80484F7: main (main.c:8)
==5118== Address 0x418a02f is 0 bytes after a block of size 7 alloc'd
==5118== at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484C3: main (main.c:6)
hello world!
==5118==
==5118== ERROR SUMMARY: 17 errors from 4 contexts (suppressed: 13 from 1)
==5118== malloc/free: in use at exit: 7 bytes in 1 blocks.
==5118== malloc/free: 1 allocs, 0 frees, 7 bytes allocated.
==5118== For counts of detected errors, rerun with: -v
==5118== searching for pointers to 1 not-freed blocks.
==5118== checked 47,492 bytes.
==5118==
==5118==
==5118== 7 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5118== at 0x402522D: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==5118== by 0x80484C3: main (main.c:6)
==5118==
==5118== LEAK SUMMARY:
==5118== definitely lost: 7 bytes in 1 blocks.
==5118== possibly lost: 0 bytes in 0 blocks.
==5118== still reachable: 0 bytes in 0 blocks.
==5118== suppressed: 0 bytes in 0 blocks.
Who can tell me why and how to fix it.
char *seq=(char *)malloc((strlen(first)+1)*sizeof(char));
You are allocating memory for a string the size of just 'first'.
strcat(strcpy(seq,first),second);
And then you try to fit both first and second in it. That's never going to work. strcat doesn't create more memory, you need to have included that in the malloc.
There is no need to cast the result of malloc in pure C.
It is also not necessary to do sizeof(char), as that is guaranteed to be 1. Some like to have it there anyway to be explict about the type in case it changes, some consider it clutter.
Where's the corresponding free() for the malloc()?
You are only allocating enough space for first in seq.
seq is only (strlen(first)+1)*sizeof(char) long, not enough to hold the concatenated string first + second.
I could see that the line :
strcat(strcpy(seq,first),second);
is not wrongly framed. The reason is, you are doing a string concatenation , where you are not giving a proper source. It will work fine, if you seggregate the above syntax into 2 lines.
strcpy(seq,first);
strcat(seq,second);
This is because, when you are doing a string copy, it will copy the string from "first" to "seq". Now, for string concatenation, since it could not find the proper source [ remember that you didnot specifically mentioned that the source is "seq" ], it is giving a invalid write memory leak problem.
Hope this clarifies your question. Please revert, if any further info is required, for the same.

Resources