I have the following very simple C program ( test.c ):
int f(int i) { return i; } int main(int argC, char* argV[]) { int x = f(12); return 1; }
I did some tests with valgrind, playing with the -fstack-check flag of the compiler on two different systems.
Testing performed on Debian 8.6 using gcc 4.9.2 and valgrind 3.10.0.
Without -fstack-check :
$ gcc test.c -o test $ valgrind ./test ==103703== Memcheck, a memory error detector ==103703== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==103703== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info ==103703== Command: ./test ==103703== ==103703== ==103703== HEAP SUMMARY: ==103703== in use at exit: 0 bytes in 0 blocks ==103703== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==103703== ==103703== All heap blocks were freed
With -fstack-check :
$ gcc -fstack-check test.c -o test $ valgrind ./test ==103726== Memcheck, a memory error detector ==103726== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==103726== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info ==103726== Command: ./test ==103726== ==103726== ==103726== HEAP SUMMARY: ==103726== in use at exit: 0 bytes in 0 blocks ==103726== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==103726== ==103726== All heap blocks were freed -- no leaks are possible ==103726== ==103726== For counts of detected and suppressed errors, rerun with: -v ==103726== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
The test was done on CentOS 6.6 using gcc 4.4.7 and valgrind 3.8.1:
Without -fstack-check :
$ gcc test.c -o test $ valgrind ./test ==16390== Memcheck, a memory error detector ==16390== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==16390== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==16390== Command: ./test ==16390== ==16390== ==16390== HEAP SUMMARY: ==16390== in use at exit: 0 bytes in 0 blocks ==16390== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==16390== ==16390== All heap blocks were freed
With -fstack-check :
$ gcc -fstack-check test.c -o test $ valgrind ./test ==16441== Memcheck, a memory error detector ==16441== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==16441== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==16441== Command: ./test ==16441== ==16441== Invalid write of size 8 ==16441== at 0x400497: main (in /home/fermin/valgrindtest/test) ==16441== Address 0x7feffd058 is not stack'd, malloc'd or (recently) free'd ==16441== ==16441== ==16441== Process terminating with default action of signal 11 (SIGSEGV) ==16441== Access not within mapped region at address 0x7FEFFD058 ==16441== at 0x400497: main (in /home/fermin/valgrindtest/test) ==16441== If you believe this happened as a result of a stack ==16441== overflow in your program main thread (unlikely but ==16441== possible), you can try to increase the size of the ==16441== main thread stack using the
In this case, in addition, the program ends with a segmentation error.
In conclusion , while everything is fine with Debian with -fstack-check , on CentOS I get a "Error" error, which I cannot explain, given the code in my program.
Considering the -fstack-check flag , perhaps the error trace is due to the stack checking mechanism allocating 8 bytes in the space heap for x , but valgrind (for some reason) cannot figure it out, so it marks it as an invalid entry. Perhaps this is a limitation in valgrind 3.8.1 that was resolved in 3.10.0 (given the fact that in the Debian setup using 3.10.0 I don't get this trace)?
In addition, I look in the frequently asked questions of the valging that " -fomit-frame-pointer and -fstack-check can degrade stack tracing," but they donβt provide too much information about the reason for this, so I canβt know if problem...
Any help or hint that helps explain this is greatly appreciated.
EDIT : as suggested in one comment, I include disassembled code for the CentOS 6.x case, compiling with -g3 and using objdump --source test . I include here the part corresponding to the main () and f () functions, however a complete dump can be found here .
Binary with -fstack-check :
0000000000400474 <f>: int f(int i) { 400474: 55 push %rbp 400475: 48 89 e5 mov %rsp,%rbp 400478: 89 7d fc mov %edi,-0x4(%rbp) return i; 40047b: 8b 45 fc mov -0x4(%rbp),%eax } 40047e: c9 leaveq 40047f: c3 retq 0000000000400480 <main>: int main(int argC, char* argV[]) { 400480: 55 push %rbp 400481: 48 89 e5 mov %rsp,%rbp 400484: 48 83 ec 20 sub $0x20,%rsp 400488: 89 7d ec mov %edi,-0x14(%rbp) 40048b: 48 89 75 e0 mov %rsi,-0x20(%rbp) int x = f(12); return 0; 40048f: 48 8d 84 24 08 d0 ff lea -0x2ff8(%rsp),%rax 400496: ff 400497: 48 c7 00 00 00 00 00 movq $0x0,(%rax) return i; } int main(int argC, char* argV[]) { int x = f(12); 40049e: bf 0c 00 00 00 mov $0xc,%edi 4004a3: e8 cc ff ff ff callq 400474 <f> 4004a8: 89 45 fc mov %eax,-0x4(%rbp) return 0; 4004ab: b8 00 00 00 00 mov $0x0,%eax } 4004b0: c9 leaveq 4004b1: c3 retq
Binary compiled without -fstack-check :
0000000000400474 <f>: int f(int i) { 400474: 55 push %rbp 400475: 48 89 e5 mov %rsp,%rbp 400478: 89 7d fc mov %edi,-0x4(%rbp) return i; 40047b: 8b 45 fc mov -0x4(%rbp),%eax } 40047e: c9 leaveq 40047f: c3 retq 0000000000400480 <main>: int main(int argC, char* argV[]) { 400480: 55 push %rbp 400481: 48 89 e5 mov %rsp,%rbp 400484: 48 83 ec 20 sub $0x20,%rsp 400488: 89 7d ec mov %edi,-0x14(%rbp) 40048b: 48 89 75 e0 mov %rsi,-0x20(%rbp) int x = f(12); 40048f: bf 0c 00 00 00 mov $0xc,%edi 400494: e8 db ff ff ff callq 400474 <f> 400499: 89 45 fc mov %eax,-0x4(%rbp) return 0; 40049c: b8 00 00 00 00 mov $0x0,%eax } 4004a1: c9 leaveq 4004a2: c3 retq
EDIT2: I tested with the latest version of valgrind currently (3.13.0) on CentOS 6.8 and I am getting the same problem.