Knowledge / Computer Science and Engineering / Exception handling and debugging

Exception handling and debugging

Computer Science and Engineering (B.E./B.Tech) · Programming · free study notes for exams, placements and interviews

In short

Exception handling is the language mechanism that detects an abnormal condition at run time, transfers control to a handler, and releases resources on the way, so a program fails predictably instead of corrupting data or crashing. Debugging is the systematic process of locating and removing the defect that produced a wrong result or an unhandled exception. Both are examined in university programming and software-engineering papers, appear as output-prediction and error-classification questions in GATE CS and in company aptitude rounds, and are tested in every technical interview at TCS, Infosys, Wipro, Cognizant, Accenture, Zoho, Flipkart, Zomato, Freshworks and the GCCs in Bengaluru, Pune and Hyderabad. On the job they decide whether a production incident takes five minutes or five hours, which is why log hygiene, stack traces and reproducible test cases are reviewed in code review.

Explained

Errors, defects and failures - the vocabulary

Mechanism: how an exception travels

  1. A throw point creates an exception object (throw, raise, or thrown by the runtime, e.g. division by zero).
  2. The runtime searches the call stack outward for the nearest enclosing try with a matching handler (match by type, derived types matching a base handler).
  3. Stack unwinding: each frame between the throw point and the handler is destroyed. In C++ automatic objects' destructors run (this is what makes RAII safe); in Java/Python/JS local references simply go out of scope and the GC reclaims them later, and finally blocks run.
  4. The handler executes; control then continues after the whole try statement - not back at the throw point (no resumption model in C++/Java/Python).
  5. If no handler is found anywhere: Java prints the stack trace and kills the thread; Python prints a traceback and exits with status 1; C++ calls std::terminate → abort.
  6. Cost model: modern C++/Java implementations are "zero-cost" on the non-throwing path (tables, not runtime checks), but a *thrown* exception is expensive. So never use exceptions for ordinary loop control in C++/Java. Python is different - for loops end via StopIteration internally, and the "easier to ask forgiveness than permission" (EAFP) style is idiomatic.

Syntax and features by language

Designing error handling well

The debugging process and tools

  1. Reproduce reliably - exact input, build, environment; shrink to a minimal failing case.
  2. Observe - read the actual message, exception type, line number and full stack trace, bottom-up to find the first frame in *your* code.
  3. Localise by divide-and-conquer - bisect the input, the code path, or the commit history (git bisect, ~log₂N builds).
  4. Form a hypothesis, make *one* change, and verify; revert if it does not help.
  5. Fix the cause, not the symptom; add a regression test that fails before and passes after; then look for the same defect pattern elsewhere.
  6. Techniques: print/trace debugging, interactive breakpoints, conditional breakpoints and watchpoints, backtracking, cause-elimination, rubber-duck explanation, post-mortem debugging from a core dump or crash log.
  7. gdb (compile with -g -O0): break file:line, run, next, step, finish, continue, print x, backtrace/bt, info locals, watch var, gdb ./a.out core.
  8. Python: python -m pdb prog.py, or breakpoint() in code; b, n, s, c, l, p/pp, w, q; traceback.print_exc(), faulthandler.
  9. Java: IDE debugger (IntelliJ/Eclipse), jdb, -XX:+HeapDumpOnOutOfMemoryError, thread dumps via jstack, jmap/VisualVM for leaks.
  10. JS: Chrome DevTools sources panel, debugger; statement, node --inspect, source maps for transpiled code.
  11. Memory and UB tools (C/C++): valgrind --leak-check=full (leaks, invalid reads/writes), AddressSanitizer/UBSan (-fsanitize=address,undefined), gcc -Wall -Wextra -Werror.
  12. Static analysis and quality gates: cppcheck, clang-tidy, pylint/flake8/mypy, ESLint, SpotBugs, SonarQube in the CI pipeline - they find defects without executing code.
  13. Logging over printing in production: levels TRACE/DEBUG/INFO/WARN/ERROR/FATAL; Python logging, Java SLF4J + Log4j2/Logback, structured JSON logs shipped to ELK/Grafana Loki. Include a correlation/request id; never log passwords, OTPs, card data, Aadhaar or other personal data. The CERT-In directions of April 2022 require Indian service providers to maintain ICT system logs (commonly cited as 180 days, within India) and report specified incidents within 6 hours; the DPDP Act 2023 adds data-minimisation duties - treat log contents as personal data. Check the current text before quoting these in practice, as compliance detail is updated.

Key points

Formulas and examples

Defect density = D / KLOC, where D = defects found and KLOC = thousands of lines of code. Unit: defects per 1,000 LOC.
Defect Removal Efficiency DRE = Dbefore / (Dbefore + Dafter) × 100 %, Dbefore = defects found before release, Dafter = defects found by users after release.
Bisection steps = ⌈log₂ N⌉, N = number of suspect commits, inputs or code regions. Unit: builds/tests.
Branch coverage = (branches executed / total branches) × 100 %; Statement coverage uses statements.
MTTR = total repair time / number of incidents; Availability = MTBF / (MTBF + MTTR).
EAFP cost = N × p × Chandle; LBYL cost = N × Ccheck; N = records, p = failure fraction, C = cost per operation.

Example 1 - Java try/catch/finally trace.

int x = 0;
try {
    x = 1;
    int[] a = new int[2];
    a[5] = 9;                 // throws ArrayIndexOutOfBoundsException
    x = 2;                    // never executed
} catch (ArrayIndexOutOfBoundsException e) {
    x = 3;
} catch (Exception e) {
    x = 4;                    // not reached: first handler matched
} finally {
    x = x + 10;
}
System.out.println(x);

Step 1: x = 1. Step 2: the bad store throws, so x = 2 is skipped. Step 3: the first matching handler sets x = 3. Step 4: finally adds 10. Output: 13.

**Example 2 - finally overriding a return.**

static int f() { try { return 1; } finally { System.out.println("cleanup"); } }   // prints cleanup, returns 1
static int g() { try { return 1; } finally { return 2; } }                        // returns 2
static int h() { try { throw new RuntimeException(); } finally { return 3; } }    // returns 3, exception discarded

In f the return value 1 is computed, then finally runs, then the method returns 1. In g the finally completes with its own return, so 2 is returned. In h the finally's return swallows the exception and the method returns 3 - which is exactly why a return inside finally is banned by most style guides.

Example 3 - C++ stack unwinding order.

struct Res { std::string n; ~Res() { std::cout << "~" << n << " "; } };
void inner() { Res b{"B"}; throw std::runtime_error("boom"); }
void outer() { Res a{"A"}; inner(); }
int main() {
    try { outer(); }
    catch (const std::exception& e) { std::cout << "caught " << e.what(); }
}

B is destroyed first (innermost frame), then A, then the handler runs. **Output: ~B ~A caught boom.** With raw new/delete instead of RAII both allocations would leak.

Example 4 - git bisect arithmetic. A regression appears somewhere in the last 2,000 commits on a 35,000-LOC service.

Example 5 - EAFP vs LBYL in Python. A batch of N = 1,00,000 records is converted with int(s); p = 2% are malformed. Suppose raising and handling one exception costs 50 µs and a pre-validating regex check costs 2 µs per record.

FeatureCC++JavaPythonJavaScript
Mechanismreturn code + errnotry/catch/throwtry/catch/finally/throwtry/except/else/finally/raisetry/catch/finally/throw
Compile-time enforcementnonenonechecked exceptionsnonenone
Cleanup idiommanual goto cleanupRAII (destructors)finally, try-with-resourceswith (context manager)finally
Catch-all-catch (...)catch (Throwable t)except BaseExceptioncatch (e)
Chaining-std::nested_exceptioninitCause / cause argraise X from eError.cause
Typical debuggergdb, Valgrind, ASangdb, ASanIDE, jdb, jstackpdbDevTools, node --inspect

Where it is used

Interview questions

Common mistakes

Related topics

C programming fundamentals · Pointers and dynamic memory · Java essentials · Python essentials · Object-oriented programming concepts · Compilation, linking and memory layout

Open in the Knowledge reader →Find jobs →