c: set malloc'd array element to NULL (invalid write) - c

I am working with parallel processes, and in one part of my code I want to fork a new process that calls the same program with slightly different arguments. For example, if the user initially called "./prog arg1 arg2 arg3", I would like to fork a new process that execs "./prog -n 1 arg2 arg3" and then that program would fork and exec "./prog -n 2 arg3." The only way I can think of doing this is using execv(), but I'm running into issues because execv requires that the last element in the argv[] array passed to it be NULL. Below is my code, and I will post the valgrind output below that.
//fork an additional process: ./prog -n (i+1) args...
// could accomplish by execv("./prog", paramlist), where paramlist is
// the same as -n (i+1) and then argv, skipping argv[1]
//create new paramlist
char **params = malloc(sizeof(char*) * argc + 2 );
sprintf(numbuf, "%d", i+1);
//./prog -n (i+1) argv[2:argc-1]
params[0] = argv[0];
params[1] = "-n";
params[2] = numbuf;
for(int i = 2; i<argc; i++){ //skip argv[0] bc we already assigned it
params[i+1] = argv[i]; //skip argv[1] because we just worked on it
}
params[argc+1] = NULL; //list must be null terminated
pid3 = fork();
if(0 == pid3){
execv("./prog", params);
exit(-1);
} //no waitpid here, because we'd like this process to continue on its own
params[argc+1] = ""; //avoid invalid free
free(params);
When I run this code normally, I get the following error:
*** Error in `./prog': free(): invalid next size (fast): 0x0000000001ac3830 ***
Valgrind tells me this:
==28067== Memcheck, a memory error detector
==28067== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28067== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==28067== Command: ./prog ./photos/photo1.jpg
==28067==
=====Displaying photo 0 (be patient.. XQuartz sucks)
Enter degrees to rotate image(0,90,180,270): 90
Enter a caption > thumb
==28067== Invalid write of size 8
==28067== at 0x400C58: main (in /usr/prog)
==28067== Address 0x51fa8d0 is 16 bytes inside a block of size 18 alloc'd
==28067== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299)
==28067== by 0x400C05: main (in /usr/prog)
==28067==
==28067== Invalid write of size 8
==28067== at 0x400CC3: main (in /usr/prog)
==28067== Address 0x51fa8d8 is 6 bytes after a block of size 18 alloc'd
==28067== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299)
==28067== by 0x400C05: main (in /usr/prog)
==28067==
==28067== Invalid write of size 8
==28067== at 0x400D0E: main (in /usr/prog)
==28067== Address 0x51fa8d8 is 6 bytes after a block of size 18 alloc'd
==28067== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299)
==28067== by 0x400C05: main (in /usr/prog)
==28067==
==28071== Syscall param execve(argv) points to unaddressable byte(s)
==28071== at 0x4F00CF7: execve (in /usr/lib64/libc-2.23.so)
==28071== by 0x400CE8: main (in /usr/prog)
==28071== Address 0x51fa8d2 is 0 bytes after a block of size 18 alloc'd
==28071== at 0x4C2BBAD: malloc (vg_replace_malloc.c:299)
==28071== by 0x400C05: main (in /usr/prog)
==28071==
==28067==
==28067== HEAP SUMMARY:
==28067== in use at exit: 0 bytes in 0 blocks
==28067== total heap usage: 5 allocs, 5 frees, 1,051,194 bytes allocated
==28067==
==28067== All heap blocks were freed -- no leaks are possible
==28067==
==28067== For counts of detected and suppressed errors, rerun with: -v
==28067== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
Interestingly, if I comment out the 'free(params)' line, then I get a segmentation fault, occurring on the line before it, 'params[argc+1] = "";' . Why is could that be?

char **params = malloc(sizeof(char*) * argc + 2 );
Should be
char **params = malloc(sizeof(char*) * (argc + 2) );

Related

`Syscall param read(buf) points to unaddressable bytes` and `address is 0 bytes after a block of n bytes alloc'd`

Valgrind is giving me bizarre output that goes away if more memory is allocated. In my program, the number I have to add to make it go away is 2064. This number appears nowhere in my program, and I have been up and down the thing for a few hours now trying to find where I could have gone wrong. No luck. Everything seems airtight, and I see no reason why an extra 2064 bytes of memory should be needed.
Thankfully, I managed to reproduce the bug in a minimal program.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv){
/* 8500 is a number I chose that is just above the generated executable size (8472)
* I double-checked after compiling and the executable is still under 8472 bytes
* You may have to choose a different size.
*/
unsigned char *p = malloc(8500);
unsigned char *pp;
FILE *fp = fopen(argv[0], "rb");
ssize_t nread;
if(p == NULL)
return 1;
pp = p;
while((nread = fread(pp, 1, 4096, fp)) > 0)
pp += nread;
free(p);
fclose(fp);
return 0;
}
The output of valgrind (and wc):
$ gcc wtf.c -Wall
$ wc -c a.out
8472
$ valgrind ./a.out
==31142== Memcheck, a memory error detector
==31142== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31142== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31142== Command: ./a.out
==31142==
==31142== Syscall param read(buf) points to unaddressable byte(s)
==31142== at 0x4F4E151: read (read.c:27)
==31142== by 0x4EC9741: _IO_file_xsgetn (fileops.c:1364)
==31142== by 0x4EBD4A0: fread (iofread.c:38)
==31142== by 0x1087CF: main (in /home/braden/code/git/bfvm2/src/a.out)
==31142== Address 0x5231174 is 0 bytes after a block of size 8,500 alloc'd
==31142== at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==31142== by 0x108782: main (in /home/braden/code/git/bfvm2/src/a.out)
==31142==
==31142==
==31142== HEAP SUMMARY:
==31142== in use at exit: 0 bytes in 0 blocks
==31142== total heap usage: 3 allocs, 3 frees, 13,148 bytes allocated
==31142==
==31142== All heap blocks were freed -- no leaks are possible
==31142==
==31142== For counts of detected and suppressed errors, rerun with: -v
==31142== ERROR SUMMARY: 2 errors from 1 contexts (suppressed: 0 from 0)
Any ideas? I don't believe there's any undefined behavior here. This isn't preventing my program from running, but it's driving me crazy, and I don't want it to turn into something serious in the future.
The valgrind message indicates an attempt to write past the end of the allocated space.
This could be coming from the call to fread requesting 4096 bytes when there is not that much space remaining in the buffer -- even though there may only be a few characters left in the input stream.
The C Standard isn't entirely clear on this matter but regardless of that it seems either:
your compiler is taking the liberty of writing to some other locations within the 4096 requested that are past the end of the allocated space, or
Valgrind is reporting an error for passing the incomplete buffer to system call read, even if the read call wouldn't have written past the end.
To avoid this, make sure the maximum extent passed to fread does not exceed the remaining buffer size, e.g. fread(pp, 1, MIN(4096, (p + 8500 - pp)), fp) where MIN is the usual minimum macro.

Valgrind leak of memory in a function that concatenates strings

I using valgrind to find a leak of memory. I wrote a function "prefix_to_string" to concatenate any two strings, but when I use the command
valgrind --leak-check=full ./helloworld
it says that I have a lot of leaks of memory. I really don't know where and why. I asked a friend why it was happening and he says that it was for doing malloc 2 times, 1 out the function and 1 in the function, but I don't know how to take care of that leak, because I think that I need to do those memory requests.
Here is the output that Valgrind gives me:
==9078== Memcheck, a memory error detector
==9078== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==9078== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==9078== Command: ./holamundo
==9078==
==9078== error calling PR_SET_PTRACER, vgdb might block
150:62
bye
==9078==
==9078== HEAP SUMMARY:
==9078== in use at exit: 63 bytes in 4 blocks
==9078== total heap usage: 5 allocs, 1 frees, 575 bytes allocated
==9078==
==9078== 5 bytes in 1 blocks are definitely lost in loss record 1 of 4
==9078== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9078== by 0x400740: prefix_to_string (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078== by 0x4008AC: main (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078==
==9078== 7 bytes in 1 blocks are definitely lost in loss record 2 of 4
==9078== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9078== by 0x400740: prefix_to_string (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078== by 0x4008C3: main (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078==
==9078== 8 bytes in 1 blocks are definitely lost in loss record 3 of 4
==9078== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9078== by 0x400740: prefix_to_string (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078== by 0x4008D8: main (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078==
==9078== 43 bytes in 1 blocks are definitely lost in loss record 4 of 4
==9078== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9078== by 0x400897: main (in /mnt/c/Users/MrRaul/desktop/Tareas_edd/test_en_C/test_informales/holamundo)
==9078==
==9078== LEAK SUMMARY:
==9078== definitely lost: 63 bytes in 4 blocks
==9078== indirectly lost: 0 bytes in 0 blocks
==9078== possibly lost: 0 bytes in 0 blocks
==9078== still reachable: 0 bytes in 0 blocks
==9078== suppressed: 0 bytes in 0 blocks
==9078==
==9078== For counts of detected and suppressed errors, rerun with: -v
==9078== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
and here is the main of my code, so this way you can reproduce the problem:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
char* prefix_to_string(char* first_string,char* second_string){
char* name = first_string;
char* extension = second_string;
char* name_with_extension;
name_with_extension = malloc(strlen(name)*(sizeof(char))+strlen(extension)*(sizeof(char))+1); /* make space for the new string (should check the return value ...) */
strcpy(name_with_extension, name); /* copy name into the new var */
strcat(name_with_extension, extension); /* add the extension */
return name_with_extension;
}
static char *itoa_simple_helper(char *dest, int i) {
if (i <= -10) {
dest = itoa_simple_helper(dest, i/10);
}
*dest++ = '0' - i%10;
return dest;
}
char *itoa_simple(char *dest, int i) {
char *s = dest;
if (i < 0) {
*s++ = '-';
} else {
i = -i;
}
*itoa_simple_helper(s, i) = '\0';
return dest;
}
int main(int argc, char *argv[]) {
int idx = 150;
int id = 62;
char str_idx[20];
char str_id[20];
itoa_simple( str_idx ,idx);
itoa_simple( str_id,id);
char *text_to_write;
text_to_write = malloc(2+sizeof(str_id)+sizeof(str_idx)+1);
text_to_write = prefix_to_string(str_idx,":");
text_to_write = prefix_to_string(text_to_write,str_id);
text_to_write = prefix_to_string(text_to_write,"\n");
printf("%s",text_to_write);
printf("bye\n");
free(text_to_write);
return 1;
}
You don't call free() often enough — you can't expect to avoid memory leaks if you don't call free() to release each separate memory allocation. And your repeated assignments to text_to_write in main() mean that you discard the only pointers to some of the allocated memory, so you can't free what was allocated. C requires endless care with memory management.
You have:
char *text_to_write;
text_to_write = malloc(2+sizeof(str_id)+sizeof(str_idx)+1);
// This assignment throws away the memory from the previous malloc
text_to_write = prefix_to_string(str_idx,":");
// This assignment throws away the memory from the previous prefix_to_string
text_to_write = prefix_to_string(text_to_write,str_id);
// This assignment also throws away the memory from the previous prefix_to_string
text_to_write = prefix_to_string(text_to_write,"\n");
printf("%s",text_to_write);
printf("bye\n");
// Calling free here only releases the last allocation from prefix_to_string
free(text_to_write);
You need something more like:
char *part1 = prefix_to_string(str_idx, ":");
char *part2 = prefix_to_string(part1, str_id);
char *part3 = prefix_to_string(part2, "\n");
printf("%s", part3);
printf("bye\n");
free(part1);
free(part2);
free(part3);

Copying a string - how do I have to deal with memory leaks and error cases?

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.

Valgrind shows more memory allocated than actually is

I was writting some simple code in C to test some memory allocation and pointers:
#include <stdlib.h>
#include <stdio.h>
int *randomAlloc(int n) {
int *address = NULL, i = 0;
address = malloc (n * sizeof(int));
for (i = 0; i < n ; i++){
*(address + i) = i ;
}
return address;
}
int main(int argc, char* argv[] ) {
int *address;
int n;
printf("Type vector size: ");
scanf("%d", &n);
address = randomAlloc(n);
free(address);
}
Yet for some reason when I type 4 as input valgrind outputs:
==2375== Memcheck, a memory error detector
==2375== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==2375== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==2375== Command: ./a.out
==2375==
Type vector size: 4
==2375==
==2375== HEAP SUMMARY:
==2375== in use at exit: 0 bytes in 0 blocks
==2375== total heap usage: 3 allocs, 3 frees, 2,064 bytes allocated
==2375==
==2375== All heap blocks were freed -- no leaks are possible
==2375==
==2375== For counts of detected and suppressed errors, rerun with: -v
==2375== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
There is only one alloc and one free at the code. As n = 4, I'd expect it to alloc 4*4(sizeof(int))=16 bytes. Where is this comming from?
Valgrind keeps track of all memory allocations which occur in your application, including ones made internally by the C library. It is not (and cannot) be limited to allocations you make explicitly, as the C library can return pointers to memory which it has allocated internally.
Many standard I/O implementations will allocate buffers for use by printf() and/or scanf(), which is probably what accounts for the numbers you're seeing.
you should only have 1 memory alloc for the 'address' pointer's memory space. the other 2 memory allocs are for the printf and scanf functions.
to proof this, comment out the printf and scanf statements and you should see 1 alloc and 1 free when you use valgrind to execute the program...

C variable initialization valgrind complains

I have a simple question here. I have some variable declarations as follows:
char long_name_VARA[]="TEST -- Gridded 450m daily Evapotranspiration (ET)";
int16 fill_PET_8day=32767;
Given the above valgrind complains for the char declaration as follows:
Invalid write of size 8
==21902== at 0x408166: main (main.c:253)
==21902== Location 0x7fe677840 is 0 bytes inside long_name_VARA[0]
and for the int16 declaration as follows:
==21902== Invalid write of size 2
==21902== at 0x408178: main (main.c:226)
Location 0x7fe677420 is 0 bytes inside local var "fill_PET_8day"
What am i doing wrong in my declarations here?
Also can I not declare a char array like this:
char temp_year[5]={0}
The warning messages you quoted show invalid memory accesses, which happen to hit memory areas belonging to the above two variables. The variables in question are victims of the error, not perpetrators. The variables are not to blame here. Nothing is wrong with the above declarations. Most likely these declarations are not in any way relevant here.
The perpetrators are lines at main.c:253 and main.c:226, which you haven't quoted yet. That's where your problem occurs.
A wild guess would be that you have another object declared after fill_PET_8day (an array?). When working with that other object, you overrun its memory boundary by ~10 bytes, thus clobbering fill_PET_8day and first 8 bytes of long_name_VARA. This is what valgrind is warning you about.
As mentioned, the declarations aren't the issue.
Although FYI, it may be better to declare your constant string as const...
const char* long_name_VARA = "TEST -- Gridded 450m daily Evapotranspiration (ET)";
or even...
const char* const long_name_VARA = "TEST -- Gridded 450m daily Evapotranspiration (ET)";
This prevents the string from being modified in code, (and the pointer).
When I run the following
/* test.c */
#include <stdio.h>
int main(void)
{
char s[8000000];
int x;
s[0] = '\0';
x=5;
printf("%s %d\n",s,x);
return 0;
}
with Valgrind I get
$ gcc test.c
$ valgrind ./a.out
==1828== Memcheck, a memory error detector
==1828== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1828== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==1828== Command: ./a.out
==1828==
==1828== Warning: client switching stacks? SP change: 0xfff0002e0 --> 0xffe85f0d0
==1828== to suppress, use: --max-stackframe=8000016 or greater
==1828== Invalid write of size 1
==1828== at 0x400541: main (in /home/m/a.out)
==1828== Address 0xffe85f0d0 is on thread 1's stack
==1828== in frame #0, created by main (???)
==1828==
==1828== Invalid write of size 8
==1828== at 0x400566: main (in /home/m/a.out)
==1828== Address 0xffe85f0c8 is on thread 1's stack
==1828== in frame #0, created by main (???)
==1828==
==1828== Invalid read of size 1
==1828== at 0x4E81ED3: vfprintf (vfprintf.c:1642)
==1828== by 0x4E88038: printf (printf.c:33)
==1828== by 0x40056A: main (in /home/m/a.out)
==1828== Address 0xffe85f0d0 is on thread 1's stack
==1828== in frame #2, created by main (???)
==1828==
5
==1828== Invalid read of size 8
==1828== at 0x4E88040: printf (printf.c:37)
==1828== by 0x40056A: main (in /home/m/a.out)
==1828== Address 0xffe85f0c8 is on thread 1's stack
==1828== in frame #0, created by printf (printf.c:28)
==1828==
==1828== Warning: client switching stacks? SP change: 0xffe85f0d0 --> 0xfff0002e0
==1828== to suppress, use: --max-stackframe=8000016 or greater
==1828==
==1828== HEAP SUMMARY:
==1828== in use at exit: 0 bytes in 0 blocks
==1828== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1828==
==1828== All heap blocks were freed -- no leaks are possible
==1828==
==1828== For counts of detected and suppressed errors, rerun with: -v
==1828== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
If I give the option Valgrind warns with I get
$ valgrind --max-stackframe=10000000 ./a.out
==1845== Memcheck, a memory error detector
==1845== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1845== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==1845== Command: ./a.out
==1845==
5
==1845==
==1845== HEAP SUMMARY:
==1845== in use at exit: 0 bytes in 0 blocks
==1845== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1845==
==1845== All heap blocks were freed -- no leaks are possible
==1845==
==1845== For counts of detected and suppressed errors, rerun with: -v
==1845== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
So the "Invalid reads/writes" are due to the large stack variable without the proper --max-stackframe=... option.

Resources