3 ms·
> Debuggers aren't very good at handling this situation. Because once the control flow jumps to the NULL page, you'd need to find a way to rewind execution hist
by planede 4y ago
> Debuggers aren't very good at handling this situation. Because once the control flow jumps to the NULL page, you'd need to find a way to rewind execution history to figure out how it got there.
This is one place where reversible debuggers shine. Try rr[1].
[1] https://rr-project.org/ https://rr-project.org/
- feffe 4y agoIn my experience debuggers handles this fine. Some archs also has a link register (jump and link) which may help finding back. This test is from x86-64 Linux. /* gcc -g -Wall -o x x.c gdb ./x (gdb) r (gdb) bt #0 0x0000000000000000 in ?? () #1 0x0000555555554617 in foo () at x.c:6 #2 0x0000555555554628 in main () at x.c:10 (gdb) f 1 #1 0x0000555555554617 in foo () at x.c:6 6 bar(); (gdb) p bar $1 = (void (*)(void)) 0x0 */ #include <stddef.h> void (*bar)(void) = NULL; void foo() { bar(); } int main() { foo(); }
- mark_undoio 4y agoIt gets worse if you have a stack smash, e.g: #include <string.h> void foo() { int array[1]; memset(array, 0, 100); /\* Oh no, trash the stack! */ } int main() { foo(); } This gets us: Program received signal SIGSEGV, Segmentation fault. 0x0000000000000000 in ?? () (gdb) bt #0 0x0000000000000000 in ?? () #1 0x0000000000000000 in ?? () But with a time travel debugger (I'm using UDB because - disclaimer - it's what I work on. `rr` would work just as well): Program received signal SIGSEGV, Segmentation fault. 0x0000000000000000 in ?? () recording 10,617> backtrace #0 0x0000000000000000 in ?? () #1 0x0000000000000000 in ?? () ^ Because we returned to NULL we have segfaulted but the stack is also trashed due to the memset. We don't know how we got here. recording 10,617> reverse-stepi 0x0000000000401146 6 } 99% 10,616> bt #0 0x0000000000401146 in foo () at smash.c:6 #1 0x0000000000000000 in ?? () ^ We've stepped back before the return, so we can now see how we got to NULL. Still incomplete stack because it's still trashed. 99% 10,616> reverse-step 5 memset(array, 0, 100); /* Oh no, trash the stack! \*/ 99% 10,586> bt #0 foo () at smash.c:5 #1 0x0000000000401155 in main () at smash.c:9 99% 10,586> ^ We've gone back before the stack smash happened, so now we get the full backtrace.
- feffe 4y agoASAN is pretty great with these cases as well. Spent much time looking for the needle in the haystack before ASAN came along.