Hacker News new | ask | show | jobs
by mark_undoio 1484 days ago
It 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.
1 comments

ASAN is pretty great with these cases as well. Spent much time looking for the needle in the haystack before ASAN came along.