Debugging 2

School of Computing Lancaster

SCC.111 Software Development - Lecture 9: Debugging II

Instructors

  • Joe Finney

  • Nigel Davies

  • Hansi Hettiarachchi

  • Adrian Friday

Lecture Overview

  • Exploration of strategies for finding logical and programming errors in code (debugging).

  • Previous week’s focus: dry running.

  • Introduction of two additional strategies for isolating problems.

  • Worked examples to illustrate concepts.

Debugging Overview

  • Debugging is likened to detective work; finding issues in code can often feel like solving a mystery.

  • A critical goal: isolate the problem to facilitate fixing it.

Importance of Runtime Errors
  • Runtime errors are problematic and need resolution.

  • Developers must aim to address these errors proactively.

Strategies for Debugging

Approach 2: Testing Hypotheses to Isolate Faults
  • Focus: Validate assumptions about code behavior.

    • Example Hypotheses to Test:

    • A variable should hold a specific value at a particular point in the source file.

    • A loop that is expected to exit does not.

    • The else clause in an if-then-else statement is the one being executed erroneously.

    • A certain function call receives the correct parameters and returns the anticipated result.

Testing Hypotheses Using printf
  • Utilizing the printf function serves as a tool for debugging, allowing programmers to output variable states and track execution flow, helping in validating hypotheses about code execution.

Consideration of Code Complexity
  • As code complexity increases, finding issues can become more challenging.

  • Introducing concepts like runtime debugging can greatly aid in dealing with complicated scenarios.

Approach 3: Runtime Debugging
  • Purpose: Designed for uncovering more elusive and complex faults within code.

  • Usage scenarios include:

    • Addressing memory corruption issues, timing or concurrency bugs, and other subtle problems.

Typical Functionality of Runtime Debuggers

  • Execution control and observation capabilities include:

    • Breakpoints: Set at specific lines or conditions to interrupt execution to check the current state.

    • Single Stepping: Step into or over functions one at a time to observe the flow of execution closely.

    • Inspecting/Changing Variables: Ability to examine variable values and modify them if necessary.

    • Watchpoints: Monitor changes to state variables, increasing visibility into how data changes over time.

Recommendations on When to Use Each Approach

  • Dry Running: Typically effective for manageable sized code units. Should be a habitual practice when reading code.

  • Printing Statements: Using debugging statements like printf can significantly help in isolating problems, particularly when dealing with smaller chunks of code. Debug print statements act as a method for code to convey its behavior.

  • Error Logs: Commonly utilized for tracking behavior in production systems, essential for identifying trends in errors or unexpected behavior.

  • Debuggers: Best suited for more complex scenarios involving confusing or unexpected runtime errors, as well as for post-crash dump analysis where deep insights into faults can be gathered.

    • Example Issues Addressed by Debuggers:

    • Memory errors (often referred to as ‘splat bugs’).

    • Concurrency issues (where processes affect one another unexpectedly).

    • Data-dependent faults (where the behavior depends on the data being processed).

Summary

  • Understanding the concept of debugging is crucial for developers.

  • Key skills to develop include:

    • Formulating and testing hypotheses regarding code execution.

    • Applying debugging statements (like printf) to systematically isolate problems.

    • Familiarity with software debuggers, which are indispensable for identifying hard-to-find errors and conducting code forensics.