Unexpected valgrind "invalid write" when using fstack-check

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 -- no leaks are possible ==103703== ==103703== For counts of detected and suppressed errors, rerun with: -v ==103703== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1) 

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 -- no leaks are possible ==16390== ==16390== For counts of detected and suppressed errors, rerun with: -v ==16390== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6) 

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 --main-stacksize= flag. ==16441== The main thread stack size used in this run was 10485760. ==16441== ==16441== HEAP SUMMARY: ==16441== in use at exit: 0 bytes in 0 blocks ==16441== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==16441== ==16441== All heap blocks were freed -- no leaks are possible ==16441== ==16441== For counts of detected and suppressed errors, rerun with: -v ==16441== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 6 from 6) 

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.

+5
source share
1 answer

I installed gcc 4.7.2 on my CentOS 6.6 system (using this procedure ) and redid the test compilation using -fstack-check :

 $ /opt/centos/devtoolset-1.1/root/usr/bin/gcc --version gcc (GCC) 4.7.2 20121015 (Red Hat 4.7.2-5) Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ /opt/centos/devtoolset-1.1/root/usr/bin/gcc -fstack-check test.c -o test $ valgrind ./test ==19374== Memcheck, a memory error detector ==19374== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al. ==19374== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info ==19374== Command: ./test ==19374== ==19374== ==19374== HEAP SUMMARY: ==19374== in use at exit: 0 bytes in 0 blocks ==19374== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==19374== ==19374== All heap blocks were freed -- no leaks are possible ==19374== ==19374== For counts of detected and suppressed errors, rerun with: -v ==19374== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6) 

Please note that now the error "incorrect record" is not displayed. So it seems that the problem is in the gcc compiler, some bug fixed between 4.4.7 and 4.7.2, like @nm in the comments.

+2
source

Source: https://habr.com/ru/post/1269220/


All Articles