Hi,
I found an (to me) odd error with address sanitizing enabled. It's on
target arm-none-linux-gnueabi (not on plain amd64-linux-gnu), tested
with gcc version 8.2.0 (GCC).
I was able to reduce it to a simple example, that exposes the same
error. The example is attached.
Short summary:
I'm constructing objects of type A in a loop. A's constructor may throw,
which is handled in the loop.
A's constructor creates a local of type std::tuple (or pair) with a size
of at least 32bytes (no error when smaller, also no error, if it's eg.
an char[32]) and one of the tuples members must have a destructor.
A also has a member, but not a plain int/char... also type with
destructor possibly.
I get an error in the loop step *after* the constructor that throws.
This is the asan error:
==3496==ERROR: AddressSanitizer: stack-use-after-scope on address
0xbef78bc0 at pc 0x00010caf bp 0xbef78b70 sp 0xbef78b74
WRITE of size 32 at 0xbef78bc0 thread T0
#0 0x10cad in A::A(int) /home/chriss/test_san/main.cpp:16
#1 0x10a5b in main /home/chriss/test_san/main.cpp:28
#2 0xb67914e7 in __libc_start_main (/lib/libc.so.6+0x174e7)
Address 0xbef78bc0 is located in stack of thread T0 at offset 32 in frame
#0 0x10be7 in A::A(int) /home/chriss/test_san/main.cpp:14
This frame has 1 object(s):
[32, 64) 'c' <== Memory access at offset 32 is inside this variable
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
/home/chriss/test_san/main.cpp:16 in A::A(int)
Shadow bytes around the buggy address:
0x37def120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def150: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x37def170: 00 00 00 00 f1 f1 f1 f1[f8]f8 f8 f8 f3 f3 f3 f3
0x37def180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def1a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def1b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x37def1c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==3496==ABORTING
asan already mentions, that this might be "a false positive if your
program uses some custom stack unwind mechanism or swapcontext" which
isnt true for me.
The program is compiled for and run on an arm cpu.
The compile flags are:
g++ -march=armv7-a -mthumb -mfpu=vfp -mfloat-abi=hard -mcpu=cortex-a5
--sysroot=... main.cpp -fsanitize=address -g
The -g flag is not needed for the error to trigger, it's just to have
linenumbers in asan output.
I (and a colleague of mine) can't see, that there is some programming
mistake. So we are suspecting a false positive from asan. Could someone
take a look at this, and tell us if this is really asans fault and if
it's a bug maybe?
BR, Christian
#include <utility>
#include <tuple>
struct B {
char a[32]; // sizeof(t) must be >=32 for fail
~B(){}; // destructor needed, all fine without
};
typedef std::tuple<B> bar;
//typedef std::pair<B, char> bar; // fails for pair, too
struct A
{
A(int i)
{
bar c; // fail here *after* a throw in previous constructor run
if (i == 7) {
throw std::exception();
}
};
B t; // this member is needed, all fine when it's not there
};
int main()
{
for (int i = 0; i < 25; ++i) {
try {
A temp(i);
} catch (std::exception&) {}
}
}