Clang address sanitizer abort
Hi,
Fedora 20 recently updated from clang 3.3 to clang 3.4. When I compiled Inkscape trunk with the new version and ran it, I immediately got an abort. I was playing around with clang a few months ago and appear to have set the CXXFLAGS to: -fsanitize=address-full,undefined,integer
Can anybody help me interpret the error message?
Thanks,
Tav
================================================================= ==22156==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff03896920 at pc 0x4617518 bp 0x7fff03896370 sp 0x7fff03896368 WRITE of size 8 at 0x7fff03896920 thread T0 #0 0x4617517 in std::_Deque_base<Geom::Affine, std::allocatorGeom::Affine >::_Deque_impl::_Deque_impl() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4617517) #1 0x46170d7 in std::_Deque_base<Geom::Affine, std::allocatorGeom::Affine >::_Deque_base() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x46170d7) #2 0x45fc91e in std::deque<Geom::Affine, std::allocatorGeom::Affine >::deque() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x45fc91e) #3 0x4c0d983 in Inkscape::Extension::Internal::PrintMetafile::PrintMetafile() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d983) #4 0x4b84106 in Inkscape::Extension::Internal::PrintEmf::PrintEmf() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4b84106) #5 0x4c0d434 in Inkscape::Extension::Internal::PrintEmf::init() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d434) #6 0x4183e6a in Inkscape::Extension::init() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4183e6a) #7 0x1f799e4 in inkscape_application_init(char const*, int) (/home/tavmjong/Sandbox_clang/bin/inkscape+0x1f799e4) #8 0x1306174 in sp_main_gui(int, char const**) (/home/tavmjong/Sandbox_clang/bin/inkscape+0x1306174) #9 0x1303496 in main (/home/tavmjong/Sandbox_clang/bin/inkscape +0x1303496) #10 0x394f021d64 in __libc_start_main (/lib64/libc.so.6 +0x394f021d64) #11 0x12ff5cc in _start (/home/tavmjong/Sandbox_clang/bin/inkscape +0x12ff5cc)
Address 0x7fff03896920 is located in stack of thread T0 at offset 96 in frame #0 0x4c0d65f in Inkscape::Extension::Internal::PrintMetafile::PrintMetafile() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d65f)
This frame has 4 object(s): [32, 40) '' [96, 176) '' <== Memory access at offset 96 is inside this variable [224, 232) '' [288, 292) '' HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-use-after-scope ??:0 std::_Deque_base<Geom::Affine, std::allocatorGeom::Affine
::_Deque_impl::_Deque_impl()
Shadow bytes around the buggy address: 0x10006070acd0: f3 f3 f3 f3 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 0x10006070ace0: f8 f8 f8 f8 f1 f1 f1 f1 00 f4 f4 f4 f3 f3 f3 f3 0x10006070acf0: f8 f8 f8 f8 00 00 00 00 00 00 00 00 00 00 00 00 0x10006070ad00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x10006070ad10: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f4 f4 f4 =>0x10006070ad20: f2 f2 f2 f2[f8]f8 f8 f8 f8 f8 f8 f8 00 00 f4 f4 0x10006070ad30: f2 f2 f2 f2 00 f4 f4 f4 f2 f2 f2 f2 04 f4 f4 f4 0x10006070ad40: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 0x10006070ad50: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 f4 f4 f4 0x10006070ad60: f3 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00 0x10006070ad70: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 ASan internal: fe ==22156==ABORTING
Hi Tav :)
Let's go over the mechanics of the address sanitizer first.
Imagine a program like this:
int main() { int *p; { int x = 0; p = &x; } return *p; }
Compiling this with the sanitizer, then running it, will produce a stack_use_after_scope error and abort the program.
Let's pick apart the sanitizer dump.
================================================================= ==22156==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fff03896920 at pc 0x4617518 bp 0x7fff03896370 sp 0x7fff03896368
%rax = 0x7fff03896920 %pc = 0x4617518 %rbp = 0x7fff03896370 %rsp = 0x7fff03896368
The value that was attempted to be accessed (probably stored in $rax, but not entirely certain) is outside the range covered by [$rbp, $rsp] (remember, stack grows downwards). Kablam, sanitizer error.
WRITE of size 8 at 0x7fff03896920 thread T0 #0 0x4617517 in std::_Deque_baseGeom::Affine, std::allocator<Geom::Affine >::_Deque_impl::_Deque_impl() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4617517) #1 0x46170d7 in std::_Deque_baseGeom::Affine, std::allocator<Geom::Affine >::_Deque_base() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x46170d7) #2 0x45fc91e in std::dequeGeom::Affine, std::allocator<Geom::Affine >::deque() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x45fc91e)
At frame 0 the PC is one before the instruction of our crash—possibly an inlined function. The program attempted to write 8 bytes to the area that once existed on the stack ($rax, 0x7fff03896920). This is fairly interesting in itself since these are all calls to the C++ STL.
#3 0x4c0d983 in Inkscape::Extension::Internal::PrintMetafile::PrintMetafile() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d983) #4 0x4b84106 in Inkscape::Extension::Internal::PrintEmf::PrintEmf() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4b84106) #5 0x4c0d434 in Inkscape::Extension::Internal::PrintEmf::init() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d434) #6 0x4183e6a in Inkscape::Extension::init() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4183e6a)
...yawn.
Address 0x7fff03896920 is located in stack of thread T0 at offset 96 in frame #0 0x4c0d65f in Inkscape::Extension::Internal::PrintMetafile::PrintMetafile() (/home/tavmjong/Sandbox_clang/bin/inkscape+0x4c0d65f)
Now it starts to get interesting. PrintMetaFile() itself is an emtpy constructor, which means all the objects the class contains are initialized with their default values.
This frame has 4 object(s): [32, 40) '' [96, 176) '' <== Memory access at offset 96 is inside this variable [224, 232) '' [288, 292) ''
8 byte item (ulonglong, maybe, or some sort of struct) Class item (this is almost certainly part of the STL, possibly std::vector) 8 byte item 4 byte item (int? intptr_t?)
std::_Deque_base<Geom::Affine, std::allocator<Geom::Affine>
::_Deque_impl::_Deque_impl()
Shadow bytes around the buggy address: ... =>0x10006070ad20: f2 f2 f2 f2[f8]f8 f8 f8 f8 f8 f8 f8 00 00 f4 f4
The f8 in brackets is the address that was attempted to be used/dereferenced.
I can't really figure out too much beyond that without a core dump of the program. I need access to the contents of $rsp and $rip to really figure out what's going on here. I suggest you look at one constructor in particular though ;)
-- View this message in context: http://inkscape.13.x6.nabble.com/Clang-address-sanitizer-abort-tp4970295p497... Sent from the Inkscape - Dev mailing list archive at Nabble.com.
On 22-Apr-2014 21:12, liamw wrote:
Imagine a program like this:
int main() { int *p; { int x = 0; p = &x; } return *p; }
Not to bad mouth the clang output too much, but it is a long, long way from what it should be, something along the lines of:
"pointer to out of scope variable at line 321 of test.c"
Unfortunately this is one of the situations where valgrind is not very helpful. Here is a slightly more complicated example:
cat >test.cpp <<EOD #include <iostream> int sub(void) { int *p; { int x = 123; p = &x; } std::cout << "value of p " << *p << std::endl; return *p; } int main() { int ret = sub(); std::cout << "value of ret " << ret << std::endl; return ret; } EOD g++ -Wall -g -O0 -o test test.cpp ./test value of p 123 value of ret 123 valgrind ./test #no problems reported
The reason the program reports these values, even though the memory is out of scope when the values are reported, is that the value stored there has not (yet) changed and the memory location has not been explicitly released. The reason valgrind doesn't complain is because it only keeps track of memory locations, not scope, and it saw that x was set, so it doesn't trigger the warning about a read from uninitialized memory. The value was probably stored on a stack because there was no explicit free() or delete() for valgrind to catch. If it were possible to make the compiler not store method/function variables on the stack then valgrind could catch these - but I don't know how to do that with the gnu compilers.
Note that if an explicit malloc/free pair was employed to emulate scope (sort of), then valgrind would have no problems detecting this issue:
cat >test.cpp <<EOD #include <iostream> #include <stdlib.h> int sub(void) { int *p; { p = (int *) malloc(sizeof(int)); *p=123; free(p); } std::cout << "value of p " << *p << std::endl; return *p; } int main() { int ret = sub(); std::cout << "value of ret " << ret << std::endl; return ret; } EOD g++ -Wall -g -O0 -o test test.cpp ./test value of p 0 value of ret 0 valgrind ./test #part of output ==2769== Invalid read of size 4 ==2769== at 0x80486E1: sub() (test.cpp:12) ==2769== by 0x804872B: main (test.cpp:16) ==2769== Address 0x432b028 is 0 bytes inside a block of size 4 free'd ==2769== at 0x402B06C: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==2769== by 0x80486DD: sub() (test.cpp:10) ==2769== by 0x804872B: main (test.cpp:16) ==2769== value of p 123 ==2769== Invalid read of size 4 ==2769== at 0x8048716: sub() (test.cpp:13) ==2769== by 0x804872B: main (test.cpp:16) ==2769== Address 0x432b028 is 0 bytes inside a block of size 4 free'd ==2769== at 0x402B06C: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==2769== by 0x80486DD: sub() (test.cpp:10) ==2769== by 0x804872B: main (test.cpp:16) ==2769== value of ret 123
This type of memory issue is discussed in some depth here:
http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-a...
Regards,
David Mathog mathog@...1176... Manager, Sequence Analysis Facility, Biology Division, Caltech
On 22-Apr-2014 21:12, liamw wrote:
int main() { int *p; { int x = 0; p = &x; } return *p; }
I asked about this on the valgrind list and the response was that g++ does not actually allocate by block scope, but rather by function scope. So in terms of what the compiler produces, the preceding program is exactly the same as:
int main() { int *p; int x = 0; p = &x; return *p; }
The main difference is that in the original form the compiler can generate warnings/errors about direct use of out of scope variables. (But not indirect, as here.) I did the experiment to verify that this was indeed the case, compiling with
g++ -Wall -ansi -O0 -S test.cpp
and with and without the braces around
int x= 0; p = &x;
and the .s files were identical. (There are slight differences if -g is added, but that is because it is adding pieces for the debugger.)
So while I have always heard is that "C++ takes care of new and delete for you" inside block scope, the reality is that with g++, it does not (ever?) do that.
Regards,
David Mathog mathog@...1176... Manager, Sequence Analysis Facility, Biology Division, Caltech
On 25-4-2014 18:58, mathog wrote:
On 22-Apr-2014 21:12, liamw wrote:
int main() { int *p; { int x = 0; p = &x; } return *p; }
I asked about this on the valgrind list and the response was that g++ does not actually allocate by block scope, but rather by function scope. So in terms of what the compiler produces, the preceding program is exactly the same as:
int main() { int *p; int x = 0; p = &x; return *p; }
The main difference is that in the original form the compiler can generate warnings/errors about direct use of out of scope variables. (But not indirect, as here.) I did the experiment to verify that this was indeed the case, compiling with
g++ -Wall -ansi -O0 -S test.cpp
and with and without the braces around
int x= 0; p = &x;
and the .s files were identical. (There are slight differences if -g is added, but that is because it is adding pieces for the debugger.)
So while I have always heard is that "C++ takes care of new and delete for you" inside block scope, the reality is that with g++, it does not (ever?) do that.
You heard wrong. AFAIK, common C++ compilers do not "new" or "delete" local variables, it puts them on the stack. Note that there is a difference between allocation/deallocation and construction/destruction. Construction and destruction happens in block scope (unoptimized). Also, your code example does not use objects, so there is no new/delete there anyway.
-Johan
mathog wrote
On 22-Apr-2014 21:12, liamw wrote:
int main() { int *p; { int x = 0; p = &x; } return *p; }
I asked about this on the valgrind list and the response was that g++ does not actually allocate by block scope, but rather by function scope. So in terms of what the compiler produces, the preceding program is exactly the same as:
int main() { int *p; int x = 0; p = &x; return *p; }
Well, no. Compilers don't have to (and shouldn't!) allocate local variables, they just put them on the stack (or in a register if it is a POD type that can fit in one).
To see why the scoping code works, I wrote an interesting program that attempts to replicate the compiler's job of local variable allocation. This is the full program: http://paste.ubuntu.com/7332558/ However, for the purposes of this demonstration I'll boil it down to the following:
/* get_sp() is a small function in the full source that retrieves the stack pointer. */ unsigned long& sub() { // sp becomes a pointer to a value on the stack unsigned long* sp = reinterpret_cast<unsigned long*>(get_sp() - PTR_S); // now assign the object *sp = 134; return *sp; }
int main() { printf("value of sub(): %lu\n", sub()); return 0; }
And this will compile and work correctly (print 134). Why!? Isn't the memory deleted when the stack is unwound?! Remember that we returned a reference to the memory, which is like a pointer and is treated like one in assembly. We called get_sp() to get the location of the stack pointer, then we wrote to that location.
When we returned the reference, the stack may have been unwound (and $rip popped into $pc), but the data still exists at the place "sp" points to. We can therefore dereference and even use it, HOWEVER, any further function calls/local variable allocations have /no guarantee *whatsoever*/ of not overwriting this value, potentially with a non-POD type that crashes on dereference. This is why a compiler warning is issued.
-- View this message in context: http://inkscape.13.x6.nabble.com/Clang-address-sanitizer-abort-tp4970295p497... Sent from the Inkscape - Dev mailing list archive at Nabble.com.
participants (4)
-
Johan Engelen
-
liamw
-
mathog
-
Tavmjong Bah