Skip to content
STIMSMITH

Exception Handling

Concept WIKI v3 · 7/29/2026

Exception handling is a cross-cutting concept that spans hardware-level CPU behavior, programming-language error-handling constructs, RISC-V assembly program generation, and RISC-V hardware extensions for control-transfer tracing. Evidence covers: (i) CPU emulator testing methodology and documented exception-handling defects; (ii) software-engineering studies of exception flows and anti-patterns in Java and C#; (iii) the CHIPS Alliance `riscv-dv` assembly generator's emission of exception-handler sections; and (iv) the RISC-V Control Transfer Records (CTR) extension, which provides hardware CSRs that explicitly classify control transfers by type, including `EXCEPTION` and `INTERRUPT` as first-class record categories.

Overview

Exception handling is a concept that spans multiple layers of computing, from hardware CPU behavior to high-level programming-language constructs. The provided evidence touches on exception handling in four distinct contexts: (i) CPU emulator testing, where exceptions are modeled as part of the abstract machine state and used to detect emulation defects; (ii) programming-language practices, where studies have examined exception flows and anti-patterns in Java and C# codebases; (iii) RISC-V assembly program generation, where the riscv-dv random instruction generator emits a dedicated exception-handling section; and (iv) RISC-V hardware extensions, where the Control Transfer Records (CTR) extension defines CSRs that classify recorded control transfers by type, treating exceptions and interrupts as distinct record categories alongside branches, calls, jumps, and returns.

Exception Handling in CPU Emulators

In CPU emulation, exceptions are an explicit component of the formal abstract machine state. A CPU state is modeled as a tuple s = (pc, R, M, E), where E is the exception state taking values from {⊥, illegal instruction, division by zero, general protection fault, ...}. The special value indicates that no exception occurred. The state-transition function δ maps s = (pc, R, M, E) into a new state s′ = (pc′, R′, M′, E′) by executing the current instruction at pc, and E′ reflects the exception status after the instruction.

Defects Observed in Emulators

The Testing CPU Emulators study (ISSTA 2009) documents several exception-handling defects in widely used emulators:

  • Pin: Not all exceptions are properly handled. Pin does not notify the emulated program about trap and illegal-instruction exceptions. Several legal instructions that raise a general-protection fault on the physical CPU are executed without generating any exception on Pin (e.g., add %ah, %fs:(%ebx)). When segment registers are pushed onto the stack, the stack pointer is not updated properly, reserving a single word where a double-word is required (e.g., push %fs).
  • Valgrind / QEMU: Instructions are not executed atomically because they are translated into several intermediate instructions. Consequently, when an exception occurs mid-instruction, the state of memory and registers may differ from the state prior to instruction execution (e.g., idiv (%ecx) with a zero divisor). Some logical instructions do not faithfully update the status register.
  • BOCHS: Certain floating-point instructions alter the state of the status register in ways that do not match the physical CPU.
  • Atomicity (physical CPU): On the physical CPU, each instruction is executed atomically; when an exception occurs, the state of memory and registers corresponds to the state preceding the instruction's execution. Deviations from this invariant in emulators constitute defects under the faithful-emulation definition used in the paper.

Page-Fault Exceptions in the EmuFuzzer Methodology

The EmuFuzzer testing methodology explicitly intercepts and uses exceptions during test-case execution. The execution of test-case code on the physical CPU continues until one of: (i) the last instruction is reached; (ii) a page-fault exception caused by an access to a missing page occurs; (iii) a page-fault exception caused by a write access to a non-writable page occurs; or (iv) any other exception occurs. Page-fault exceptions are used for lazy memory synchronization: during the initialisation phase, all data pages of the physical environment are protected, and when an instruction tries to access memory, the page-fault exception is intercepted to retrieve the corresponding memory page from the emulated environment.

On the physical CPU side, the test-case runs through a small user-space program that registers signal handlers for page faults and other runtime exceptions, and the test-case code is executed as a shellcode. The emulator is extended with embedded code that (a) intercepts the beginning and end of each basic block or instruction of the emulated program, (b) intercepts exceptions that may occur during execution, and (c) provides an interface to access the values of the CPU registers and the memory content of the emulator.

Exception Handling Practices in Programming Languages

Modern programming languages such as Java and C# provide exception-handling features that separate error-handling code from regular source code. These features are designed to enhance software reliability, comprehension, and maintenance, but their misuse can still cause reliability degradation or catastrophic software failures such as application crashes.

Exception Flow Analysis Findings

A 2017 study analyzed over 10,000 exception handling blocks and over 77,000 related exception flows from 16 open-source Java and C# (.NET) libraries and applications. Key findings:

  • Each try block has up to 12 possible potentially recoverable yet propagated exceptions.
  • 22% of distinct possible exceptions can be traced back to multiple methods (average of 1.39 and maximum of 34).
  • There is a notable lack of documentation of the possible exceptions and their sources, but such critical information can be identified by exception-flow analysis on well-documented API calls (e.g., JRE and .NET documentation).
  • Different exception-handling strategies are observed between Java and C#.
  • The findings highlight the opportunity to leverage automated software analysis to assist exception-handling practices and signify the need for further in-depth studies.

Common Anti-Patterns

A companion 2017 study collected a thorough list of exception anti-patterns from the same set of 16 open-source Java and C# libraries and applications, using an automated exception-flow analysis tool. Although exception-handling anti-patterns widely exist across all subjects, only a few anti-patterns are commonly identified:

  • Unhandled Exceptions
  • Catch Generic
  • Unreachable Handler
  • Over-catch
  • Destructive Wrapping

The prevalence of these anti-patterns also illustrates differences between C# and Java, calling for further in-depth analyses of exception-handling practices across languages.

Exception Handling in RISC-V Assembly Generation

In the CHIPS Alliance riscv-dv random instruction generator, the riscv_asm_program_gen class generates RISC-V assembly programs that include a dedicated exception-handling section. The generated program is described as containing multiple sections: initialization routine, instruction section, data section, stack section, page table, interrupt handling, and exception handling, each produced by different functions within riscv_asm_program_gen.

Generation Flow

The function gen_program() is the main routine that generates the full RISC-V assembly program by calling other functions in the class. After the main and any subprogram generation is complete, host-interface instructions are added through gen_section (with labels such as write_tohost and _exit). The flow then calls push_gpr_to_kernel_stack(), which pushes general-purpose registers to the stack for trap handling. riscv_asm_program uses gen_section() to select the instruction string mtvec_handler, which has exception_handler and interrupt_handler defined within it.

Relationship to gen_section

gen_section is directly involved in assembling named code sections used by the generated program. In the exception-handling path, it selects the mtvec_handler string that contains the exception_handler and interrupt_handler definitions.

Exception Handling in RISC-V Verification Flows

In RISC-V CPU verification practice, exception paths are recognized as one of the critical behavioral areas that must be exercised by the verification environment. Random instruction generation (such as riscv-dv) is noted as effective only when tied to a coverage strategy that explicitly addresses privilege transitions, debug entry, exceptions, interrupts, CSRs, PMP-like protection features, and custom instructions. Random tests can hit instruction combinations, but they do not automatically prove that the project has exercised meaningful state transitions or software-facing corner cases, so coverage models are recommended to identify which exception paths must be observed.

Lockstep co-simulation is highlighted as operationally important because alignment between the DUT, reference model, and checker must be maintained on architectural state at instruction retirement, including control flow and exception-handling paths. When lockstep, trace hooks, or debug-state validation are added late, teams can lose weeks localizing divergence in trap behavior, retirement correctness, or corner-case sequencing.

Exceptions in the RISC-V Control Transfer Records Extension

The RISC-V Control Transfer Records (CTR) extension defines hardware support for recording control-flow events, with exceptions and interrupts treated as first-class record categories distinct from ordinary branches, calls, jumps, and returns.

CTR CSRs and Privilege Modes

The extension adds CSRs at multiple privilege levels:

  • M-mode: CSR_MCTRCTL (0x34e)
  • S-mode: CSR_SCTRCTL (0x14e), CSR_SCTRSTATUS (0x14f), CSR_SCTRDEPTH (0x15f)
  • VS-mode: CSR_VSCTRCTL (0x24e)

A convenience alias maps CSR_CTRCTL to either CSR_MCTRCTL or CSR_SCTRCTL depending on whether CONFIG_RISCV_M_MODE is set, mirroring the same M/S aliasing pattern used for CSR_TOPEI/CSR_TOPI.

Exception- and Interrupt-Specific Control Bits

The xctrctl CSR exposes per-privilege enable bits (CTRCTL_U_ENABLE, CTRCTL_S_ENABLE, CTRCTL_M_ENABLE) and a CTRCTL_RASEMU bit (0x80) for RAS emulation. Two bits directly govern the recording of trap-related events:

  • CTRCTL_EXCINH (bit 37, value 0x200000000) — inhibit exception records
  • CTRCTL_INTRINH (bit 38, value 0x400000000) — inhibit interrupt records
  • CTRCTL_TRETINH (bit 39, value 0x800000000) — inhibit trap-return records

These bits allow software to selectively suppress exception, interrupt, and trap-return records, separating them from the other CTRCTL control bits that govern branch and call/return recording (e.g., CTRCTL_INDCALL_INH, CTRCTL_DIRCALL_INH, CTRCTL_INDJUMP_INH, CTRCTL_RET_INH).

Record Type Classification: Exception vs. Interrupt

The CTR extension classifies each recorded transfer into one of sixteen CTRDATA_TYPE_* categories. The type field is masked by CTRDATA_TYPE_MASK (0xF), and exceptions and interrupts are given dedicated type values:

  • CTRDATA_TYPE_EXCEPTION = 1
  • CTRDATA_TYPE_INTERRUPT = 2
  • CTRDATA_TYPE_TRAP_RET = 3

These are listed alongside branches (CTRDATA_TYPE_NONTAKEN_BRANCH = 4, CTRDATA_TYPE_TAKEN_BRANCH = 5), reserved values 6–7, and the various call, jump, co-routine swap, and return types (8–15). The dedicated EXCEPTION and INTERRUPT type codes, together with the per-record flags CTRSOURCE_VALID and CTRTARGET_MISP, and the cycle-counting fields CTRDATA_CCV, CTRDATA_CCM_MASK, and CTRDATA_CCE_MASK, allow post-mortem analysis tools to identify the specific trap that triggered an exception record and to disambiguate exceptions from ordinary control flow.

Buffer Sizing and Storage

The sctrdepth CSR selects the depth of the record buffer, encoded by SCTRDEPTH_MASK (0x7). SCTRDEPTH_MIN (0x0) corresponds to 16 entries, and SCTRDEPTH_MAX (0x4) corresponds to 256 entries. The sctrstatus CSR exposes the write pointer via SCTRSTATUS_WRPTR_MASK (0xFF) and a freeze bit SCTRSTATUS_FROZEN (0x80000000). The actual record storage occupies CSR addresses CTR_ENTRIES_FIRST (0x200) through CTR_ENTRIES_LAST (0x2ff), giving 256 entries of hardware-mapped record storage at the top of the CSR address space.

CITATIONS

10 sources
10 citations
[1] The Testing CPU Emulators study (ISSTA 2009) documents exception-handling defects in Pin, Valgrind, QEMU, and BOCHS, including missing exception notification in Pin, non-atomic instruction translation in Valgrind/QEMU, status-register deviations in BOCHS, and the physical CPU invariant that each instruction executes atomically with state preserved across exceptions. Testing CPU Emulators
[2] The EmuFuzzer methodology intercepts page-fault and runtime exceptions during test-case execution on both the physical CPU and emulator, and uses page-fault exceptions for lazy memory synchronization by protecting data pages and retrieving them on first access. Testing CPU Emulators
[3] A CPU abstract-machine state is modeled as a tuple s = (pc, R, M, E) where E is the exception state, with ⊥ indicating no exception and other values such as illegal instruction, division by zero, and general protection fault denoting specific exceptions. Testing CPU Emulators
[4] A 2017 study analyzed over 10,000 exception handling blocks and over 77,000 related exception flows from 16 open-source Java and C# (.NET) libraries and applications, finding that each try block has up to 12 possible potentially recoverable yet propagated exceptions, 22% of distinct possible exceptions trace back to multiple methods (average 1.39, maximum 34), and that there is a notable lack of documentation of possible exceptions. Revisiting Exception Handling Practices with Exception Flow Analysis
[5] A 2017 study collected exception anti-patterns from 16 open-source Java and C# libraries and applications using an automated exception-flow analysis tool, finding that only a few anti-patterns are commonly identified — Unhandled Exceptions, Catch Generic, Unreachable Handler, Over-catch, and Destructive Wrapping — with differences in prevalence between C# and Java. Studying the Prevalence of Exception Handling Anti-Patterns
[6] The RISC-V CTR extension adds CSRs CSR_MCTRCTL (0x34e), CSR_SCTRCTL (0x14e), CSR_SCTRSTATUS (0x14f), CSR_SCTRDEPTH (0x15f), and CSR_VSCTRCTL (0x24e), with a CSR_CTRCTL alias that maps to CSR_MCTRCTL or CSR_SCTRCTL depending on CONFIG_RISCV_M_MODE. [PATCH RFC 2/6] riscv: perf: Add Control transfer records CSR definations. — Linux Perf Users
[7] The CTR extension's xctrctl CSR exposes CTRCTL_EXCINH (0x200000000), CTRCTL_INTRINH (0x400000000), and CTRCTL_TRETINH (0x800000000) bits to selectively inhibit recording of exceptions, interrupts, and trap returns, alongside per-privilege enable bits and branch/call/return inhibit bits. [PATCH RFC 2/6] riscv: perf: Add Control transfer records CSR definations. — Linux Perf Users
[8] The CTR extension classifies recorded transfers using CTRDATA_TYPE values, with CTRDATA_TYPE_EXCEPTION = 1, CTRDATA_TYPE_INTERRUPT = 2, and CTRDATA_TYPE_TRAP_RET = 3 reserved as first-class record categories distinct from branches (4–5), reserved values (6–7), and call/jump/co-routine/return types (8–15). [PATCH RFC 2/6] riscv: perf: Add Control transfer records CSR definations. — Linux Perf Users
[9] The sctrdepth CSR selects record-buffer depth with SCTRDEPTH_MIN (0x0) corresponding to 16 entries and SCTRDEPTH_MAX (0x4) corresponding to 256 entries, and the sctrstatus CSR exposes SCTRSTATUS_WRPTR_MASK (0xFF) and SCTRSTATUS_FROZEN (0x80000000), with record storage located at CSR addresses CTR_ENTRIES_FIRST (0x200) through CTR_ENTRIES_LAST (0x2ff). [PATCH RFC 2/6] riscv: perf: Add Control transfer records CSR definations. — Linux Perf Users
[10] In RISC-V verification practice, exception paths are recognized as a critical area that must be exercised, and coverage models are recommended to identify which exception paths, privilege transitions, debug entries, and CSR interactions must be observed beyond what random instruction generation alone produces. RISC-V Verification: Five places projects lose weeks

VERSION HISTORY

v3 · 7/29/2026 · minimax/minimax-m3 (current)
v2 · 6/7/2026 · minimax/minimax-m3
v1 · 5/27/2026 · gpt-5.5