Sunday, June 3, 2012

Ch.5 Debugging


  • A lot of ways to improve design and development, but none of them could eliminate all bugs.
    • Reduce connection and interaction between software components
      • Information hiding
      • Abstraction
      • Interfaces
      • Language features to support above items
    • Integrity of a software design
      • Program proofs
      • Modeling
      • Requirement analysis
      • formal verification
  • Techniques to reduce debugging time
    • Good design
    • Good style
    • Boundary condition tests,
    • Assertions and sanity checks in the code
    • Defensive programming
    • Well-designed interfaces
    • Limited global data
    • Checking Tools
  • Debuggers
    • Debugger are system dependent
    • Programs are not well handled by debuggers, just by lower level approaches.
      • Multi-process/multi-thread programs
      • Operating systems
      • Distributed systems
    • Bug killer is always coders, not the debuggers!
      • Coders must own the blue graph in mind to find bugs.
      • Blind probing with a debugger shouldn't be productive.
        • Stepping through a program is less productive than thinking harder and adding output statements and self-checking code at critical places.
  • What's the lower level approach
    • Just print them!
    • Binary search
      • Data
      • Code
  • Debugging experience
    • Good clues, easy bugs
      • Look for familiar patterns
        • Common bugs have distinctive signatures
        • Example: Fail to initialize local varable
          • declaration
          • malloc/realloc
      • Examine the most recent change
        • Version control system is powerful here.
      • Don't make the same mistake twice
        • If it occurs, then it might have the same one somewhere else.
      • Debug it now, not later
        • As I was both the task leader and the RD, in the other words, I had to be responsible for tracking other's bugs/development progress, fixing my bugs, and keeping to write my modules. It had the blind spot that I couldn't distinguish priority clearly between bugs' severity level and development progress, deadline. I judged some un-crashed issue and weird behavior to be low priority. Sad! In the day of released version population, we were more painful to fix them. It was the terrible experience.
          • If I am just the developer, I will focus on fixing all bugs
          • If I am just the manager, I put the deadline in higher priority.
          • If I am both of them, I need much more experience to find the balance or the experienced advisor.
        • If you can't do it now, just list them on schedule in the most obvious place!
      • Get a stack trace
        • The trail of function call
        • Arguments
        • Line numbers
      • Read before typing
        • What you see in the source code is what you meant rather than what you wrote!
          • Take a break to jump out of the mental barrier
        • Resist the urge to start typing: thinking is a worthwhile alternative
      • Explain your code to someone else or puppet
        • Reorganize thought.
    • No clues, hard bugs
      • Make the bug reproducible
        • Decrease the time spent waiting for bug happened, then find it faster
          • Make the bug appeared on demand!
      • Divide and conquer
        • Narrow down the possibilities by creating the smallest input where bug still show up
        • Proceed by binary search
          • Code
          • Data
      • Study the numerology of failures
        • Failing examples give us the clue and point out the track to find bugs.
      • Display output to localize your search
        • Each message should be distinct so you can tell which one you are looking at.
        • Easy to use the message with other tools: like grep, string parser. compression tool.
        • Two pointer has the same value, or they are the same pointer?
          • %x, %p.
      • Write self-checking code
        • Check function
          • test conditions.
          • dump relevant variables, data structures.
          • abort the program.
        • Not only for debugging, leave check function during all stages of development.
      • Write a log file
        • Fixed format stream to the debugging output.
        • I/O to files: setbuf/setvbuf
          • Buffer
            • flush
            • When crashed...
              • core dump
              • final flush!
          • Unbuffer
            • overhead 
      • Draw a picture
        • Figure out programs deeply by annotating the data structures with statistics and plotting it!
      • Use tools
        • Learn them in anytime and anywhere if needed!
          • Investment!
      • Keep records
        • When bug occurred, record them!
          • root cause.
          • where to be changed
          • related issues
          • Commit CL
        • One of the sources of test cases. 
  • Non-reproducible bugs
    • Write outside of memory
    • All vars initialized
    • Double free
      • Compiler support option to assert immediately!
    • Work fine on my side, but fail on another side!
      • Environment!
  • Other people's bugs
    • Organize the program, and original parameters in and out!
      • Debugger could point out it!
    • Check the frequent changed section!
    • Point out other's bug?
      • Kindly discussion
      • Risk of credit and time!
    • Make sure the bug is new!
    • Platform bugs
      • Try tests on multiple systems and check platform/compiler definition
        • ex: shift operation filled with zero bits or sign bits?
    • Report them in nice format!
      • The best sample: The ones that need only a line or two of input on a plain vanilla system to demonstrate the fault, and includes the fix.
  • Summary
    • Classes of bugs
      • Good clues, easy bugs
      • No clues, hard bugs
      • Non-reproducible bugs
      • Other people's bugs
    • Steps
      • Look for familiar patterns
      • Examine the most recent change
      • Don't make the same mistake twice
      • Debug it now, not later
      • Get a stack trace
      • Read before typing
      • Explain your code to someone else or puppet
      • Make the bug reproducible
      • Divide and conquer
      • Study the numerology of failures
      • Display output to localize your search
      • Write self-checking code
      • Write a log file
      • Draw a picture
      • Use tools
      • Keep records
    • Make myself to fix bugs much more effectively in the next time.