{"id":26,"date":"2003-06-03T18:02:59","date_gmt":"2003-06-03T17:02:59","guid":{"rendered":"http:\/\/www.nobugs.org\/blog\/archives\/2003\/06\/03\/stunt-debugging-with-c\/"},"modified":"2003-06-03T18:02:59","modified_gmt":"2003-06-03T17:02:59","slug":"stunt-debugging-with-c","status":"publish","type":"post","link":"https:\/\/www.nobugs.org\/blog\/archives\/2003\/06\/03\/stunt-debugging-with-c\/","title":{"rendered":"Stunt Debugging with C++"},"content":{"rendered":"<p>I&#8217;ve used the DevStudio debugger for years.  Until today, an &#8220;access violation&#8221; dialog  meant &#8220;game over&#8221;.  You could poke around with the debugger to find out why your application crashed, but since your application was already dead, it was basically just a  post-mortem.  And then today, I realised that you can often ressurect the program &#8230;<br \/>\n<!--more--><br \/>\nI&#8217;ve been trying to get away from the dreaded &#8220;edit-compile-test&#8221; cycle in C++, since restarting the application is very time consuming.  I&#8217;d already mentally reinvented the DevStudio edit-and-continue feature (indirect function calls through a table, and preallocate extra space in each stack frame so you can introduce new locals) before I realised Microsoft had already got there.  <\/p>\n<p>Having said that, I&#8217;d previously vowed never to use edit-and-continue again.  When it works, everything is great.  But eventually, it&#8217;ll fail in some subtle way.  Inevitably, that&#8217;ll leave you with a subtely corrupted .exe and I&#8217;ve spend hours chasing phantom bugs before finally giving in and doing a &#8220;rebuild all&#8221;.  Incremental development works fine with lisp\/ocaml\/smalltalk.  I don&#8217;t understand what&#8217;s so hard to make it work all the time under C++.  Grr.<\/p>\n<p>But today, I started using it again because incremental development is just so nice, and I&#8217;ve been spoiled by using languages.  So, I happily edited my code and it happily updated my still-running image.  Everything went well, until I suffered a thinko and the application crashed.  D&#8217;oh!<\/p>\n<p>But I wasn&#8217;t prepared to give in that easily.  It takes a while to restart the application and get it into the correct state.  I&#8217;d been enjoying &#8220;edit and continue&#8221; so much that I was determined to have &#8220;crash and continue&#8221; too.  Hey, if it works with lisp\/smalltalk then why not in C++.<\/p>\n<p>And then it struck me that my crashed application wasn&#8217;t dead after all.  Sure, it&#8217;d suffered a null-pointer dereference, but the debugger had caught that and now I was looking at the disassembly for the bad dereference.  I realised that it was possible to <i>carefully<\/i> reposition the instruction pointer to run the function epilogue (where it unwinds the stack and restores saved registers) and then manually set a return value by altering eax.  Yay, my application restarted and continued as if nothing had happened.  To finish the job, I used edit-and-continue to fix the buggy bit of code before it got executed again.<\/p>\n<p>&#8220;Crash and continue&#8221; has been achieved. \ud83d\ude42<\/p>\n<p>It won&#8217;t always be possible to resurrect a program in this manner.  Sometimes you have to manually unwind more than one stack frame.  Sometimes, there&#8217;s some invariant which needs to be fixed up (like, releasing critical sections).  But it&#8217;s often possible to get your application to limp back up to the message loop (or similar point) which gives you a chance to patch up your code and have another go.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve used the DevStudio debugger for years. Until today, an &#8220;access violation&#8221; dialog meant &#8220;game over&#8221;. You could poke around with the debugger to find out why your application crashed, but since your application was already dead, it was basically just a post-mortem. And then today, I realised that you can often ressurect the program [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-26","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/posts\/26","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/comments?post=26"}],"version-history":[{"count":0,"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/posts\/26\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/media?parent=26"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/categories?post=26"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nobugs.org\/blog\/wp-json\/wp\/v2\/tags?post=26"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}