1
votes

Several of the Sanitizers (from either GCC or Clang) cannot be combined – i.e. used simultaneously in the same build, but Asan and Ubsan are combinable – i.e. I can build with “-fsanitize=address,undefined -fsanitize-recover=all …” and have an exe that performs the checks from both sanitizers. All good so far.

The LOGGING from the resulting executable seems problematic though.

In all cases, if ‘log_path’ is not set in the options, the defects all get reported on stderr. OK so far. Try to use log_path though, and things get strange:

  • For an exe built just with Asan, and setting ASAN_OPTIONS to include “log_path=./ASAN”, the Address Saniitizer defects will go into a file named ASAN.
  • For an exe built just with Ubsan, and setting UBSAN_OPTIONS to include “log_path=./UBSAN”, the Undefined Behavior defects will go into a file named UBSAN.
  • For an exe built with both Asan and Ubsan o The Asan output goes to the designated log file, but the ubsan output goes only to stderr o The above applies even if the log_path is only set via UBSAN_OPTIONS, and ASAN_OPTIONS is unset o If log_path is set in both ASAN_OPTIONS and UBSAN_OPTIONS, the log_path used is the UBSAN one, yet only contains the ASAN results

Is there some hidden magic that will let both sanitizers write to the same defect log ?


To reproduce, use a simple testcase that has a defect for each sanitizer:

char *hello = "hello";

int main (int argc, char *argv[])
{
   int x = 1;
   x <<= 32; // Error: (1 << 32) can't be represented in a (32-bit) int
   char some_char = hello [argc *10];
}

build and run: (g++ 7.3.0 used here, but other GCC versions, and also clang 7.1.0 have shown the same basic behavior)

Asan only - works as expected

g++ foo.C -fsanitize=address -fsanitize-recover=all -g
setenv ASAN_OPTIONS "log_path=./ASAN:halt_on_error=0:handle_abort=1:exitcode=0"
a.out 

File ASAN. 29648 contains defect starting with

==29648==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000400aca at pc 0x0000004009a5 bp 0x7fffffffe090 sp 0x7fffffffe088

READ of size 1 at 0x000000400aca thread T0 0x4009a4 in main /tmp/foo.C:7

Ubsan only - works as expected

g++ foo.C -fsanitize=undefined -fsanitize-recover=all -g
setenv UBSAN_OPTIONS "log_path=./UBSAN:halt_on_error=0:handle_abort=1:exitcode=0”
a.out

File UBSAN.29675 contains

foo.C:6:6: runtime error: shift exponent 32 is too large for 32-bit type 'int'

Asan PLUS Ubsan - strange logging behavior

g++ foo.C -fsanitize=address,undefined -fsanitize-recover=all -g

setenv ASAN_OPTIONS "log_path=./ASAN:halt_on_error=0:handle_abort=1:exitcode=0"
a.out 

ASAN_OPTIONS gets ignored, all defects reported on stderr. Now try setting UBSAN_OPTIONS:

setenv UBSAN_OPTIONS "log_path=./UBSAN:halt_on_error=0:handle_abort=1:exitcode=0”
a.out

File UBSAN.30352 contains ONLY the Asan defect:

==30352==ERROR: AddressSanitizer: global-buffer-overflow on address 0x000000400aca at pc 0x0000004009a5 bp 0x7fffffffe090 sp 0x7fffffffe088 READ of size 1 at 0x000000400aca thread T0 0x4009a4 in main /tmp/foo.C:7

and the Ubsan defect gets written only to stderr:

foo.C:6:6: runtime error: shift exponent 32 is too large for 32-bit type 'int'

3

3 Answers

0
votes

and the Ubsan defect gets written only to stderr:

This sounds like a bug (or at least untested combination of settings).

That said, in general, ASan developers do not consider halt_on_error=0 to be a useful feature -- you should just fix the bugs as you find them, as it is pointless to look for UB after you've already overflown a buffer or used dangling memory. Anything could happen after that point.

So if you do file a bug about this strange logging behavior, I would expect that bug to receive little attention.

0
votes

Have confirmed that this is actually a bug. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94328 applies

0
votes

I have been searching for a way to use AddressSantizer with avr-gcc where there is no console to detect that the runtime code has crashed. I still have to experiment with it, but I believe this use case is a counter example to this feature not being useful.