I have searched high and low for an applicable answer, but I couldn't find one. I am well aware my inability to solve this issue is due to a unfamiliarity of C.
I am working on a function to concatenate one dynamically allocated string onto another, and it seems to work outside the realm of memory leaks and valgrind; however, when I run it with valgrind it is evident I have some glaring memory leaks I just cannot find. It seems to be a issue with how I am using realloc.
here is the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void dynamCat(char *dest, const char *src) {
size_t len = strlen(dest) + strlen(src) + 1;
printf("strLen: %ld\n", len);
char *tmp = realloc(dest, len);
if(tmp == NULL){
fprintf(stderr, "strAppend: realloc messed up\n");
free(tmp);
return;
} else {
dest = tmp;
}
strcat(dest, src);
}
int main (int argc, char *argv[]) {
char *one = malloc(4);
strcpy(one, "tee");
char *two = malloc(4);
strcpy(two, "hee");
printf("one: %s\n", one);
printf("two: %s\n", two);
dynamCat(one, two);
printf("one: %s\n", one);
printf("two: %s\n", two);
//freeee
free(one);
free(two);
return 0;
}
the output on the command line:
$ ./dynamCat
one: tee
two: hee
strLen: 7
one: teehee
two: hee
here's where the bad stuff comes.
output with valgrind on the commandline:
==28804== Memcheck, a memory error detector
==28804== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==28804== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==28804== Command: ./dynamCat
==28804==
==28804== Invalid read of size 1
==28804== at 0x4841C72: strlen (vg_replace_strmem.c:459)
==28804== by 0x48D9407: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804== by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804== by 0x1092EE: main (dynamCat.c:37)
==28804== Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804== Block was alloc'd at
==28804== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804== by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804== at 0x4841C84: strlen (vg_replace_strmem.c:459)
==28804== by 0x48D9407: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804== by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804== by 0x1092EE: main (dynamCat.c:37)
==28804== Address 0x4a3c041 is 1 bytes inside a block of size 4 free'd
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804== Block was alloc'd at
==28804== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804== by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804== at 0x48460D0: mempcpy (vg_replace_strmem.c:1536)
==28804== by 0x48ED211: _IO_file_xsputn##GLIBC_2.2.5 (in /usr/lib/libc-2.33.so)
==28804== by 0x48D915A: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804== by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804== by 0x1092EE: main (dynamCat.c:37)
==28804== Address 0x4a3c042 is 2 bytes inside a block of size 4 free'd
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804== Block was alloc'd at
==28804== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804== by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid read of size 1
==28804== at 0x48460DE: mempcpy (vg_replace_strmem.c:1536)
==28804== by 0x48ED211: _IO_file_xsputn##GLIBC_2.2.5 (in /usr/lib/libc-2.33.so)
==28804== by 0x48D915A: __vfprintf_internal (in /usr/lib/libc-2.33.so)
==28804== by 0x48C463E: printf (in /usr/lib/libc-2.33.so)
==28804== by 0x1092EE: main (dynamCat.c:37)
==28804== Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804== Block was alloc'd at
==28804== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804== by 0x10926D: main (dynamCat.c:26)
==28804==
==28804== Invalid free() / delete / delete[] / realloc()
==28804== at 0x483F9AB: free (vg_replace_malloc.c:538)
==28804== by 0x109312: main (dynamCat.c:41)
==28804== Address 0x4a3c040 is 0 bytes inside a block of size 4 free'd
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804== Block was alloc'd at
==28804== at 0x483E77F: malloc (vg_replace_malloc.c:307)
==28804== by 0x10926D: main (dynamCat.c:26)
==28804==
==28804==
==28804== HEAP SUMMARY:
==28804== in use at exit: 7 bytes in 1 blocks
==28804== total heap usage: 4 allocs, 4 frees, 4,111 bytes allocated
==28804==
==28804== 7 bytes in 1 blocks are definitely lost in loss record 1 of 1
==28804== at 0x4840D7B: realloc (vg_replace_malloc.c:834)
==28804== by 0x1091FA: dynamCat (dynamCat.c:11)
==28804== by 0x1092D6: main (dynamCat.c:35)
==28804==
==28804== LEAK SUMMARY:
==28804== definitely lost: 7 bytes in 1 blocks
==28804== indirectly lost: 0 bytes in 0 blocks
==28804== possibly lost: 0 bytes in 0 blocks
==28804== still reachable: 0 bytes in 0 blocks
==28804== suppressed: 0 bytes in 0 blocks
==28804==
==28804== For lists of detected and suppressed errors, rerun with: -s
==28804== ERROR SUMMARY: 9 errors from 6 contexts (suppressed: 0 from 0)
thank you so much for your help. I am still very new to C and really appreciate your help.
If realloc returns a null pointer, do not free its return value; there is no point in passing a null pointer to free:
char *tmp = realloc(dest, len);
if(tmp == NULL){
fprintf(stderr, "strAppend: realloc messed up\n");
free(tmp); // This does nothing.
dest is a parameter, so assigning to it changes only the parameter. It does not change the original argument:
dest = tmp; // This changes only the dest inside dynamCat.
To give the caller a new address, you must either return it as a pointer:
char *dynamCat(char *dest, const char *src)
{
…
dest = something;
…
return dest;
}
or you must put it into a pointer passed by the caller:
void dynamCat(char **dest, const char *src)
{
…
char *tmp = realloc(*dest, len);
…
*dest = tmp;
}
strcat(*dest, src);
}
In the latter case, when calling dynamCat, you must pass it the address of a pointer:
dynamCat(&one, two);
In the former case, you must take the new pointer from the return value of dynamCat:
one = dynamCat(one, two);
The realloc function can change the address of the object. When he object is being made bigger, the need for this is obvious: there may not be space at the original location. It's potentially true when shrinking the object also.
In abstract terms, when we call realloc(x, newsize), the pointer x becomes indeterminate. We must capture the returned pointer y = realloc(x, newsize) and then use that in all places that previously referred to x.
In your program the catenating function returns void, and main keeps referring to the old string.
Your dynamCat should be like this:
/* dest is destroyed: use the return value
* in place of dest!
*/
char *dynamCat(char *dest, const char *src) {
size_t len = strlen(dest) + strlen(src) + 1;
printf("strLen: %ld\n", len);
char *tmp = realloc(dest, len);
if(tmp == NULL){
fprintf(stderr, "strAppend: realloc messed up\n");
/* better handling needed here, too */
}
strcat(tmp, src);
return tmp;
}
Related
I'm writing a C program which will determine if a given string is a semidrome (concatenation of 2 or more palindromes), and while my solution does work, I keep getting Valgrind errors that don't make any sense to me. I'm fairly new to C and valgrind, and while I generally understand what the errors mean, I don't see how they apply to my code.
Here's my code :
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// Function to check if a given string is a palindrome
int isPalindrome(char str[]) {
int len = strlen(str);
if (len == 1){return 0;}
int left = 0;
int right = len - 1;
while (right > left) {
if (str[left++] != str[right--]) {
return 0;
}
}
return 1;
}
bool is_semidrome(char *s) {
int len = strlen(s);
// If empty string, automatically not a semidrome
if(len == 0){return 0;}
// If palindrome, automatically a semidrome
if(isPalindrome(s)){return 1;}
// Initialize two arrays to check if a substring is a palindrome
char *palcheck, *palcheckrest;
for (int i = 1; i < len; i++){
// Go through the array until we find a char same as s[0] (potential palindrome)
if (s[0] == s[i]){
// make an array of the potential palindrome
palcheck = malloc((i+2)*sizeof(char));
palcheck = strncpy(palcheck, s, i+1);
palcheck[i+1] = '\0';
// if it is a palindrome, recursively check if the rest is a semidrome
if (isPalindrome(palcheck)){
// make a new substring with the rest of the string
palcheckrest = malloc((len - i)*sizeof(char));
for (int j = 0; j < (len - i - 1); j++){
palcheckrest[j] = s[j+i+1];
}
palcheckrest[len - i] = '\0';
// if it is a semidrome, return true
if (is_semidrome(palcheckrest)){
free(palcheck);
free(palcheckrest);
return true;}
else{
free(palcheck);
free(palcheckrest);
// if i is the ending index and we still haven't found a potential palindrome, return false
if(i == len){
return false;}
// if i is not the ending index, keep checking
else{
free(palcheck);
free(palcheckrest);
continue;}
}}
else {
free(palcheck);
continue;}
}
}}
Here's the valgrind errors :
Input:
popeye==152438== Memcheck, a memory error detector
==152438== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==152438== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==152438== Command: ./student_answer
==152438==
==152438== Invalid write of size 1
==152438== at 0x10A3CE: is_semidrome (semidrome.c:39)
==152438== by 0x10A1EB: main (main.c:11)
==152438== Address 0x4a73154 is 0 bytes after a block of size 4 alloc'd
==152438== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==152438== by 0x10A377: is_semidrome (semidrome.c:35)
==152438== by 0x10A1EB: main (main.c:11)
==152438==
==152438== Conditional jump or move depends on uninitialised value(s)
==152438== at 0x483EF58: strlen (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==152438== by 0x10A2B4: is_semidrome (semidrome.c:23)
==152438== by 0x10A3DC: is_semidrome (semidrome.c:40)
==152438== by 0x10A1EB: main (main.c:11)
==152438==
==152438== Conditional jump or move depends on uninitialised value(s)
==152438== at 0x483EF58: strlen (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==152438== by 0x10A230: isPalindrome (semidrome.c:9)
==152438== by 0x10A2D3: is_semidrome (semidrome.c:25)
==152438== by 0x10A3DC: is_semidrome (semidrome.c:40)
==152438== by 0x10A1EB: main (main.c:11)
==152438==
==152438==
==152438== HEAP SUMMARY:
==152438== in use at exit: 0 bytes in 0 blocks
==152438== total heap usage: 5 allocs, 5 frees, 8,250 bytes allocated
==152438==
==152438== All heap blocks were freed -- no leaks are possible
==152438==
==152438== Use --track-origins=yes to see where uninitialised values come from
==152438== For lists of detected and suppressed errors, rerun with: -s
==152438== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
I know I don't have the most efficient or elegant solution, but the focus at the moment is understanding how to fix the Valgrind errors.
Look at your code. Valgrind is telling you what you did wrong.
==152438== Invalid write of size 1
==152438== at 0x10A3CE: is_semidrome (semidrome.c:39)
==152438== by 0x10A1EB: main (main.c:11)
==152438== Address 0x4a73154 is 0 bytes after a block of size 4 alloc'd
==152438== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==152438== by 0x10A377: is_semidrome (semidrome.c:35)
"a block of size 4 alloc'd .... is_semidrome (semidrome.c:35)"
So this is where you allocated something with a size of 4 bytes.
"Invalid write of size 1 ... is_semidrome (semidrome.c:39)"
And this is where you wrote to the 5th byte in that block of memory.
You can't write 5 bytes into 4 bytes of space.
The most likely fix is to add 1 to the size of the allocation that you did on line 35.
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 should dynamically allocate an array of pointers to structure, passing from time to time parameters for a single structure.
sorry if I can not explain, here is the code
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
typedef struct _DROP_DOWN_MENU_LABELS
{
char *title;
char **items;
} MenuLabels;
MenuLabels ** ml_init(void)
{
MenuLabels **ml;
ml=(MenuLabels **)calloc(2,sizeof(MenuLabels*));
ml[1]=NULL;
return ml;
}
void addit(MenuLabels **mlabels, char *title, char *elems,...)
{
int j;
for (j=0; mlabels[j]!=NULL ; j++ );
printf("\n\nCHECK:MenuLabels has %d menu",j);
mlabels=(MenuLabels **)realloc(mlabels,(j+2)*sizeof(MenuLabels*));
mlabels[j]=(MenuLabels *)malloc(1*sizeof(MenuLabels));
mlabels[j+1]=NULL;
mlabels[j]->title=title;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int i=0;
char **mitems=NULL;
mitems=(char **)malloc(sizeof(char*));
mitems[i]=elems;
va_list argP;
va_start(argP, elems);
char *p;
for (i=1; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=p;
}
if (!p)
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=NULL;
}
va_end(argP);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
mlabels[j]->items=mitems;
}
int main()
{
MenuLabels **ml;
ml=ml_init();
addit(ml,"FILE","new","open","save","backup","print","setup","exit",NULL);
addit(ml,"AFILE","Anew","Asave","Abackup","Aexit",NULL);
addit(ml,"BFILE","Bnew","Bopen","Bsave","Bprint","Bexit",NULL);
free(ml);
fprintf(stdout,"\n\033[1;91m***END***\033[0m\n");
return 0;
}
starting the program seems to be executed without errors:
CHECK:MenuLabels has 0 menu
CHECK:MenuLabels has 1 menu
CHECK:MenuLabels has 2 menu
***END***
Process returned 0 (0x0) execution time : 0.001 s
Press ENTER to continue.
but checking with valgrind:
==5572== Memcheck, a memory error detector
==5572== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5572== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==5572== Command: ./prove
==5572==
==5572== Invalid read of size 8
==5572== at 0x400812: addit (main.c:26)
==5572== by 0x400B27: main (main.c:75)
==5572== Address 0x5204040 is 0 bytes inside a block of size 16 free'd
==5572== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x400855: addit (main.c:29)
==5572== by 0x400AF1: main (main.c:74)
==5572== Block was alloc'd at
==5572== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x40075C: ml_init (main.c:15)
==5572== by 0x400AB0: main (main.c:73)
==5572==
CHECK:MenuLabels has 0 menu
==5572== Invalid free() / delete / delete[] / realloc()
==5572== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x400855: addit (main.c:29)
==5572== by 0x400B27: main (main.c:75)
==5572== Address 0x5204040 is 0 bytes inside a block of size 16 free'd
==5572== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x400855: addit (main.c:29)
==5572== by 0x400AF1: main (main.c:74)
==5572== Block was alloc'd at
==5572== at 0x4C2FB55: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x40075C: ml_init (main.c:15)
==5572== by 0x400AB0: main (main.c:73)
==5572==
==5572== Invalid write of size 8
==5572== at 0x400882: addit (main.c:31)
==5572== by 0x400B27: main (main.c:75)
==5572== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==5572==
==5572==
==5572== Process terminating with default action of signal 11 (SIGSEGV)
==5572== Access not within mapped region at address 0x0
==5572== at 0x400882: addit (main.c:31)
==5572== by 0x400B27: main (main.c:75)
==5572== If you believe this happened as a result of a stack
==5572== overflow in your program's main thread (unlikely but
==5572== possible), you can try to increase the size of the
==5572== main thread stack using the --main-stacksize= flag.
==5572== The main thread stack size used in this run was 8388608.
CHECK:MenuLabels has 0 menu==5572==
==5572== HEAP SUMMARY:
==5572== in use at exit: 112 bytes in 4 blocks
==5572== total heap usage: 14 allocs, 10 frees, 1,392 bytes allocated
==5572==
==5572== 16 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5572== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x400881: addit (main.c:31)
==5572== by 0x400B27: main (main.c:75)
==5572==
==5572== 96 (16 direct, 80 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==5572== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5572== by 0x400855: addit (main.c:29)
==5572== by 0x400AF1: main (main.c:74)
==5572==
==5572== LEAK SUMMARY:
==5572== definitely lost: 32 bytes in 2 blocks
==5572== indirectly lost: 80 bytes in 2 blocks
==5572== possibly lost: 0 bytes in 0 blocks
==5572== still reachable: 0 bytes in 0 blocks
==5572== suppressed: 0 bytes in 0 blocks
==5572==
==5572== For counts of detected and suppressed errors, rerun with: -v
==5572== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)
./run_valgrind: riga 4: 5572 Errore di segmentazione (core dump creato) valgrind --leak-check=full --track-origins=yes --tool=memcheck ./prove
and in fact if I try to extract any value from ml at the end (eg ml[n]-> title) it goes into segmentation fault
what am I doing wrong? thank you all in advance
Here's one problem:
char **mitems;
// ... assuming there's a mitems = malloc(...) or similar here...
mlabels[j]->items=mitems;
free(mitems);
Here you have a a pointer, you make it point to some memory you allocate, you copy the pointer (so you have two pointers pointing to the same memory) and then you free the memory that both pointers are pointing to.
The free call makes not only mitems invalid, but also mlabels[j]->items.
I solved ... here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
typedef struct s_drop_down_menu_labels
{
char *title;
char **items;
} MenuLabels;
MenuLabels ** ml_init(void)
{
MenuLabels **ml;
ml=(MenuLabels **)calloc(2,sizeof(MenuLabels*));
ml[1]=NULL;
return ml;
}
void addit(MenuLabels ***mlabels, char *title, char *elems,...)
{
int j;
for (j=0; (*mlabels)[j]!=NULL ; j++ );
printf("\n\nCHECK:MenuLabels has %d menu",j);
*mlabels=(MenuLabels **)realloc(*mlabels,(j+2)*sizeof(MenuLabels*));
(*mlabels)[j]=(MenuLabels *)malloc(1*sizeof(MenuLabels));
(*mlabels)[j+1]=NULL;
(*mlabels)[j]->title=title;
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int i=0;
char **mitems=NULL;
mitems=(char **)malloc(sizeof(char*));
mitems[i]=elems;
va_list argP;
va_start(argP, elems);
char *p;
for (i=1; ((p=va_arg(argP,char*)) !=NULL) ; i++ )
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=p;
}
if (!p)
{
mitems=(char **)realloc(mitems,(i+1)*sizeof(char*));
mitems[i]=NULL;
}
va_end(argP);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
(*mlabels)[j]->items=mitems;
free(mitems);
}
int main()
{
MenuLabels **ml;
ml=ml_init();
addit(&ml,"FILE","new","open","save","backup","print","setup","exit",NULL);
addit(&ml,"AFILE","Anew","Asave","Abackup","Aexit",NULL);
addit(&ml,"BFILE","Bnew","Bopen","Bsave","Bprint","Bexit",NULL);
addit(&ml,"CFILE","Cnew","Copen","Csave","Cbackup","Cprint","Csetup","Cexit",NULL);
addit(&ml,"DFILE","Dnew","Dsave","Dbackup","Dexit",NULL);
addit(&ml,"EFILE","Enew","Eopen","Esave","Eprint","Eexit",NULL);
printf("\n**********CHECK: %s",ml[3]->title);
for (int i=0;ml[i]!=NULL ;i++ )
free(ml[i]);
fprintf(stdout,"\n\033[1;91m***END***\033[0m\n");
return 0;
}
#Some_programmer_dude, if not free mitems then there will be no more accessible memory allocated ...thank you all
I'm trying to read in words from a text file in C using fscanf and putthem into a dynamically allocated array. However, I keep getting errors in Valgrind and (null) characters seem to be popping up in my output. I create a double pointer **str_array to hold each character array and initially allocate enough space for 4 character arrays. fscanf runs and stores the read in string into str[] and I use strcpy to copy str[]'s string into str_array. I realloc memory if str_array needs to hold more strings.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[80];
int word_alloc = 0;
int word_count = 0;
char **str_array;
FILE *file;
file = fopen(argv[1], "r");
// Allocate memory to the array of strings (char arrays)
word_alloc = 4;
str_array = (char **) malloc(sizeof(char*) * word_alloc);
while (fscanf(file, "%s", str) != EOF) {
// If there are more than 4 strings, double size
if (word_count > word_alloc) {
word_alloc *= 2;
str_array = (char **) realloc(str_array, sizeof(char*) * word_alloc);
}
str_array[word_count] = (char *) malloc(sizeof(char) * (strlen(str) + 1));
strcpy(str_array[word_count], str);
++word_count;
}
int i = 0;
for (; i<word_count; i++) {
printf("Word: %s\n", str_array[i]);
}
i = 0;
for (; i<word_count; i++) {
free(str_array[word_count]);
}
free(str_array);
fclose(file);
return 0;
}
Here's the Valgrind error code.
==6254== Memcheck, a memory error detector
==6254== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6254== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==6254== Command: ./a.out readin-test.txt
==6254==
==6254== Invalid write of size 8
==6254== at 0x4008A6: main (readin-test.c:25)
==6254== Address 0x51fc2e0 is 0 bytes after a block of size 32 alloc'd
==6254== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x400835: main (readin-test.c:16)
==6254==
==6254== Invalid read of size 8
==6254== at 0x4008C0: main (readin-test.c:26)
==6254== Address 0x51fc2e0 is 0 bytes after a block of size 32 alloc'd
==6254== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x400835: main (readin-test.c:16)
==6254==
==6254== Conditional jump or move depends on uninitialised value(s)
==6254== at 0x4C2BDA2: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x40094A: main (readin-test.c:37)
==6254== Uninitialised value was created by a heap allocation
==6254== at 0x4C2CE8E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x400871: main (readin-test.c:22)
==6254==
==6254==
==6254== HEAP SUMMARY:
==6254== in use at exit: 999 bytes in 173 blocks
==6254== total heap usage: 181 allocs, 8 frees, 5,631 bytes allocated
==6254==
==6254== 999 bytes in 173 blocks are definitely lost in loss record 1 of 1
==6254== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6254== by 0x4008A5: main (readin-test.c:25)
==6254==
==6254== LEAK SUMMARY:
==6254== definitely lost: 999 bytes in 173 blocks
==6254== indirectly lost: 0 bytes in 0 blocks
==6254== possibly lost: 0 bytes in 0 blocks
==6254== still reachable: 0 bytes in 0 blocks
==6254== suppressed: 0 bytes in 0 blocks
==6254==
==6254== For counts of detected and suppressed errors, rerun with: -v
==6254== ERROR SUMMARY: 186 errors from 4 contexts (suppressed: 0 from 0)
You have an error in the free loop:
i = 0;
for (; i<word_count; i++) {
free(str_array[word_count]);
}
The array index should be i, not word_count.
I want to read in from the arguments a file with a name of format filename.in and output a file with the exact same filename but with .out extension instead of .in (filename.out). The key is that filename can be anything.
This code compiles correctly and does the job I want, but when I run it with valgrind I get a bunch of errors. Can anyone tell me what's causing the errors?
int main(int argc, char * argv[])
{
int i, dotIndex;
char extOut[] = ".out";
char *filenameIn, *filenameOut, *aux;
FILE *fpIn, *fpOut;
filenameIn = argv[1];
aux = strchr(filenameIn, '.');
dotIndex = aux - filenameIn;
aux = (char *)malloc((strlen(filenameIn) - 1)*sizeof(char));
for(i = 0; i < dotIndex; i++)
aux[i] = filenameIn[i];
filenameOut = (char *)malloc((strlen(aux) + 5)*sizeof(char));
strcat(aux, extOut);
strcpy(filenameOut, aux);
/* open input file */
fpIn = fopen(filenameIn,"r");
if(fpIn == NULL) {
printf("Open error of input file\n");
exit(2);
}
/* open output file */
fpOut = fopen(filenameOut,"w");
if(fpOut == NULL) {
printf("Open error of output file\n");
exit(3);
}
fclose(fpOut);
fclose(fpIn);
free(aux);
free(filenameOut);
exit(0);
}
The valgrind report:
Command: ./doorsmaze text.in
==3493==
==3493== Invalid write of size 1
==3493== at 0x402C36B: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487AB: main (main.c:64)
==3493== Address 0x41ef02e is 0 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493== Invalid write of size 1
==3493== at 0x402C390: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487AB: main (main.c:64)
==3493== Address 0x41ef030 is 2 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493== Invalid read of size 1
==3493== at 0x402C6C5: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487BF: main (main.c:65)
==3493== Address 0x41ef02e is 0 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493==
==3493== HEAP SUMMARY:
==3493== in use at exit: 0 bytes in 0 blocks
==3493== total heap usage: 4 allocs, 4 frees, 719 bytes allocated
==3493==
==3493== All heap blocks were freed -- no leaks are possible
==3493== Command: ./doorsmaze text.in
==3493==
==3493== Invalid write of size 1
==3493== at 0x402C36B: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487AB: main (main.c:64)
==3493== Address 0x41ef02e is 0 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493== Invalid write of size 1
==3493== at 0x402C390: strcat (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487AB: main (main.c:64)
==3493== Address 0x41ef030 is 2 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493== Invalid read of size 1
==3493== at 0x402C6C5: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x80487BF: main (main.c:65)
==3493== Address 0x41ef02e is 0 bytes after a block of size 6 alloc'd
==3493== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==3493== by 0x8048716: main (main.c:55)
==3493==
==3493==
==3493== HEAP SUMMARY:
==3493== in use at exit: 0 bytes in 0 blocks
==3493== total heap usage: 4 allocs, 4 frees, 719 bytes allocated
==3493==
==3493== All heap blocks were freed -- no leaks are possible
==3493==
==3493== For counts of detected and suppressed errors, rerun with: -v
==3493== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 0 from 0)
==3493== For counts of detected and suppressed errors, rerun with: -v
==3493== ERROR SUMMARY: 6 errors from 3 contexts (suppressed: 0 from 0)
You have some issues in your code
You might not get the last . in the filename
aux = strchr(filenameIn, '.');
better use strrchr. You should also check for NULL, just in case the filename doesn't include an extension.
You allocate memory large enough to hold filename.in (excluding the nul byte)
aux = (char *)malloc((strlen(filenameIn) - 1)*sizeof(char));
You do your own version of strncpy(aux, filenameIn, dotIndex)
for(i = 0; i < dotIndex; i++)
aux[i] = filenameIn[i];`
You write beyond the allocated buffer, because you miss the space for the last character plus the nul byte
strcat(aux, extOut);
To fix this, you must allocate enough memory, which is the length of filename.in plus 1 char ("out" is one longer than "in") plus nul byte
aux = (char *)malloc((strlen(filenameIn) + 2)*sizeof(char));