libasan: possible false positive?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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&) {}
	}
}

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux