I am using address sanitizers in conjunction with gtest. I have a test that which references a unique_ptr that is null and subsequently fails.
Edit: as pointed out in the comments, this ub. For simplicities sake, assume a nullcheck is present and raises a signal when the ptr ist null.
This is intended by the test and part of the design. My test contains the following line:
ASSERT_EXIT(..., ::testing::KilledBySignal(SIGSEGV),".*")
Without sanitizer, the test passes. With sanitizer, it fails, I get the following feedback from the sanitizer:
actual msg:
[ DEATH ] AddressSanitizer:DEADLYSIGNAL
[ DEATH ] =================================================================
[ DEATH ] ==13242==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x55d0c75eb50f bp 0x7ffdd011b540 sp 0x7ffdd011b520 T0)
[ DEATH ] ==13242==The signal is caused by a READ memory access.
[ DEATH ] ==13242==Hint: address points to the zero page.
This looks to me as if the sanitizer detects the SIGSEGV signal. The problem is: the signal is there by design and intended to be there. Is there a way to configure asan to ignore this?
This looks to me as if the sanitizer detects the SIGSEGV signal. The problem is: the signal is there by design and intended to be there.
That's not the problem. The problem is that after detecting the signal, the sanitizer runtime performs exit(1), which causes the process to exit differently, and the ASSERT_EXIT detects that the child process did not in fact die with SIGSEGV.
Is there a way to configure asan to ignore this?
Not really.
There is an abort_on_error=1 which you could add to ASAN_OPTIONS environment variable, which will cause the child process to die with SIGABRT, but that still wouldn't satisfy your ASSERT_EXIT.
In general, DEATH_TESTs are rarely worth the paper they are written on, and certainly getting them to work under AddressSanitizer is pointless.
You can skip this test by compiling it conditionally (i.e. compile it out when -fsanitize=address is in effect). Documentation on how to achieve that.
Related
Hello I use MacBook M1 (OSX) and I have a dangling pointer which it seems I can't catch.
I am using Clion and LLDB as a debuger.
When I run my code I get:
Exception: EXC_BAD_ACCESS (code=1, address=0x18)
However this does not really shows me or I can't understand where exactly is the bad pointer.
I am attaching also screenshot of my editor and the debugger window:
I have read something about zombie objects which when enabled allows you to catch dangling pointers. How can I do that?
EXC_BAD_ACCESS (defined in /usr/include/mach/exception_types.h) has a code (which is a kern_return_t) and a subcode. kern_return_t is defined in /usr/include/mach/kern_return.h and 1 means KERN_INVALID_ADDRESS, so this was not a protection problem but an actual invalid address access. The subcode (0x18) is the address accessed.
A small number like 0x18 usually means that your code accessed a field that was 0x18 bytes into an object, but the object pointer was null. So the first thing to do is look at all the accesses in that line of code (or around it if you are debugging optimized code) and make sure none of them are null. This might also be a null vtable, and the 0x18 the vtable offset, i.e. one of the methods of the object, so look for calls as well. However, I didn't see any suspicious looking pointer values in your locals, so maybe it's some subobject?
If it isn't obvious from there which pointer is bad, you could run your code under ASAN (address sanitizer) - if the bad pointer access is because of a use after free ASAN will often find those quickly. Note, Zombie objects is an ObjC only thing, that doesn't look relevant in your code.
If that doesn't get it, the most straightforward way to diagnose this sort of error is to look at the disassembly, for instance just run:
(lldb) disassemble
The current PC will be marked in the output. That instruction will be some kind of memory access, often dereferencing a register with an offset or something like that. For instance:
ldr w9, [x9, #0x18]
is loading memory 0x18 bytes off from the value in register x9. If this were the instruction, the next question is what program entity is currently occupying x9? lldb might know, you can ask it by doing:
(lldb) image lookup -va $pc
That will tell you everything lldb knows about that pc, among other things the last set of entries will be where all the known variables are currently located. Look for one that is in x9. If there isn't one listed in x9, then maybe one of the currently visible variables was temporarily copied into x9, in which case you have to look up in the instruction stream to see what was the last value that got copied into x9.
I am using a syscall checker in combination with -fsanitize=address and when ASAN finds a bug, it calls some syscalls (ioctl(ISATTY), etc) when printing out the report. The syscall checker interrupts ASAN's ioctls and the error report is not collected properly.
What I would like is for ASAN to simply abort without printing the report, or failing that, a way to determine (using a libasan4 API call maybe) that ASAN found an error, so I can stop the syscall checker from intercepting syscalls.
Unfortunately __asan_error_report, __sanitizer_set_death_callback and __asan_set_error_report_callback from libasan4 all kick in after ASAN has collected the report:
0 __asan_error_report()
1 syscall_checker()
2 ioctl(ISATTY)
3 asan::PrintReport()
4 app_code_that_crashes()
And the syscall checker does not handle ASAN's ioctl() calls properly, so it exit()s normally, while I am hoping to keep ASAN's behavior of abort()ing.
You should be able to intercept before report is printed by overriding __asan_on_error (declared in asan_interface.h, empty by default):
// User may provide function that would be called right when ASan detects
// an error. This can be used to notice cases when ASan detects an error, but
// the program crashes before ASan report is printed.
void __asan_on_error();
Note that due to weird Asan callback interface you'd better implement this callback in main binary (definitions in shared libraries are likely to be unable to intercept default definition from libasan.a).
I have my code ready to run with PROOF.
Whenever I run code standalone I works fine, when I activate PROOF, my code crash with a Segmentation Fault.
With GDB I'm able to know exactly where it crashes: when I try to follow a pointer to a object. This makes me think that this pointer (that I'm absolutely sure it was valid before) is invalid and I have no idea why so.
Are there other options? can I track that pointer so I know where it was released?
Use valgrind memcheck tool with --leak-check=summary --track-origins=yes.
This shows invalid memory access (Segmentation Fault) and where they had been freed.
I am examining a few crashes that all have the signal SIGSEGV with the reason SEGV_ACCERR. After searching for SEGV_ACCERR, the closest thing I have found to a human readable explanation is: Invalid Permissions for object
What does this mean in a more general sense? When would a SEGV_ACCERR arise? Is there more specific documentation on this reason?
This is an error that I have mostly seen on 64 bit iOS devices and can happen if multiple threads read and change a variable under ARC. For example, I fixed a crash today where multiple background threads were reading and using a static NSDate and NSString variable and updating them without doing any kind of locking or queueing.
Using core data objects on multiple threads can also cause this crash, as I have seen many times in my crash logs.
I also use Crittercism, and this particular crash was a SEGV_ACCERR that only affected 64 bit devices.
As stated in the man page of sigaction, SEGV_ACCERR is a signal code for SIGSEGV that specifies Invalid permissions for mapped object. Contrary to SEGV_MAPERR which means that the address is not mapped to a valid object, SEGV_ACCERR means the address matches an object, but for sure it is neither the good one, nor one the process is allowed to access.
I've seen this in cases where code tries to execute from places other than "text".
For eg, if your pointer is pointing to a function in heap or stack and you try to execute that code (from heap or stack), the CPU throws this exception.
It's possible to get a SEGV_ACCERR because of a stack overflow. Specifically, this happened to me on Android ARM64 with the following:
VeryLargeStruct s;
s = {}; // SEGV_ACCERR
It seems that the zero-initialization created a temporary that caused a stack overflow. This only happened with -O0; presumably the temporary was optimized away at higher optimization levels.
On android arm64 if stack.cpp contains:
struct VeryLargeStruct {
int array[4096*4096];
};
int main() {
struct VeryLargeStruct s;
s = {};
}
and typing:
aarch64-linux-android26-clang++ -std=c++20 -g -DANDROID_STL=c++_static -static-libstdc++ stack.cpp -o stack
adb push stack /data/local/tmp
adb shell /data/local/tmp/stack
/data/tombstones/tombstone_01 contains a SEGV_MAPERR, not SEGV_ACCERR:
id: 11363, tid: 11363, name: stack >>> /data/local/tmp/stack <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x7ff2d02dd8
I get SEGV_ACCERR, when const.c contains:
int main() {
char *str="hello";
str[0]='H';
}
Then /data/tombstones/tombstone_00 contains:
pid: 9844, tid: 9844, name: consts >>> /data/local/tmp/consts <<<
Signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x55d10674e8
I am running a program in multi threaded environment it fails at some point. when i tried it with gdb than it is shoing the following error.
program received signal SIGSEGV, segmentation fault.
[switching to thread 0x7fff677b700 (LWP 2777)] 0x00007ffff7aa42b9 in
process_incomplete_rows (resultset=0x507950) at c/mgmt.c:479 479
c/mgmt.c: No such file or directory.
mgmt.c file is there and this code is working fine for some options but 2 or three options its giving this error. What could be the cause of this error. Its error in comiplation or in coe? or its error while accessing some data?
A segmentation fault is a runtime error that is usually due to referencing an invalid pointer. Usually that invalid pointer has never been initialized, but sometimes it is reusing an old pointer or writing past the end of an allocated memory chunk (such as past the end of a string).
It probably means that your node variable is either NULL or corrupted. Run your program in the debugger, stepping through it from some point prior to the crash up until it and see where you've messed it up. Or use one of the automated tools like Purify or Insure++ to track it down for you.