cpp-debugging
Use when a C++ failure involves memory lifetime, undefined behavior, native crashes, or debugger-only state — debug with symbols, sanitizers, and platform-native debuggers before patching symptoms
Best use case
cpp-debugging is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when a C++ failure involves memory lifetime, undefined behavior, native crashes, or debugger-only state — debug with symbols, sanitizers, and platform-native debuggers before patching symptoms
Teams using cpp-debugging should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/cpp-debugging/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How cpp-debugging Compares
| Feature / Agent | cpp-debugging | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when a C++ failure involves memory lifetime, undefined behavior, native crashes, or debugger-only state — debug with symbols, sanitizers, and platform-native debuggers before patching symptoms
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# C++ Debugging `systematic-debugging` gives you the language-neutral method. This skill adds the native C++ toolchain and runtime techniques that matter once the bug involves crashes, corrupted memory, UB, or platform-specific debugger state. ## When to Use - A C++ process crashes with a segmentation fault, access violation, or abort - The bug depends on object lifetime, ownership, or move/copy behavior - Behavior changes between debug and release builds - AddressSanitizer, UndefinedBehaviorSanitizer, or a debugger is needed to see the failure clearly - A native test hangs, deadlocks, or corrupts memory without a clear stack trace ## When NOT to Use | Instead of cpp-debugging | Use | |--------------------------|-----| | You still do not have a stable reproduction or root-cause workflow | `systematic-debugging` | | The failure is a build, compile, or link error | `fix-build-errors` | | The issue is performance-only, not correctness | `performance-optimization` | ## Prerequisites - A reproducible failing command, test, or executable - A debug-capable build with symbols - Access to the relevant debugger or sanitizer-enabled toolchain - Enough context to tell whether the bug is runtime, lifetime, concurrency, or build-related ## Workflow ### 1. Rebuild for diagnosis, not speed Start with a debuggable build before chasing the crash: ```powershell # CMake cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug cmake --build build --config Debug # Clang/GCC direct build example clang++ -std=c++20 -g -O0 -Wall -Wextra -Wpedantic main.cpp -o app.exe ``` Guidelines: - enable symbols (`-g`, `/Zi`) - reduce or disable optimization while reproducing (`-O0`, `/Od`) - keep warnings enabled - reproduce with the same inputs that fail in CI or production-like runs ### 2. Capture the exact failing surface ```powershell # Run the failing binary or test under the same conditions each time ctest --test-dir build --output-on-failure # Or run the specific executable directly .\build\app.exe ``` Record: 1. exact command line 2. failing input or fixture 3. crash signal or exit code 4. first bad log line, assertion, or stack frame ### 3. Inspect runtime state with a native debugger Use the platform-native debugger your team standardizes on. Common flows: ```powershell # GDB gdb --args .\build\app.exe <args> # (gdb) run # (gdb) bt # (gdb) frame 0 # (gdb) info locals # (gdb) p suspiciousVariable # LLDB lldb -- .\build\app.exe <args> # (lldb) run # (lldb) bt # (lldb) frame variable ``` Focus on: - the first frame where state becomes invalid - moved-from or already-destroyed objects - container bounds and iterator validity - null or dangling pointers - cross-thread ordering when the state only fails under load ### 4. Turn on sanitizers early Sanitizers catch the class of bugs that ordinary logging often hides. ```powershell # Clang/GCC cmake -S . -B build-asan ` -DCMAKE_BUILD_TYPE=Debug ` -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer" cmake --build build-asan ctest --test-dir build-asan --output-on-failure ``` If your toolchain supports it, enable the equivalent native flags on Windows as well (for example MSVC AddressSanitizer in supported versions). Use sanitizer output to answer: - which access was invalid - which allocation/free site owned the memory - whether UB happened before the visible crash ### 5. Use core dumps or crash artifacts when the bug is post-mortem If the crash only appears outside the current shell, collect the artifact and inspect it: ```text - preserve the crashing binary and symbols - keep the exact build that produced the dump - load the dump in the matching debugger - compare the crashing frame with the last known good run ``` Do not "fix" a crash dump by guessing from the top frame alone. Trace ownership and state backwards. ### 6. Fix the root cause and harden the boundary Typical C++ root causes: - lifetime mismatch between owner and borrower - invalid iterator or reference after container mutation - double free or use-after-free - missing synchronization around shared mutable state - undefined behavior surfaced by a newer compiler or optimizer After the fix: - rerun the failing reproduction - rerun sanitizer-enabled tests - add a regression test where practical - check nearby code for the same lifetime or ownership pattern ## Common Rationalizations | Rationalization | Reality | |----------------|---------| | "The debugger changes timing, so it is useless" | Timing-sensitive bugs still need debugger or sanitizer evidence. Use them to narrow the class of failure, then confirm in a normal run. | | "Release-only crash means the optimizer is broken" | Most release-only failures are UB, data races, or lifetime bugs that debug mode accidentally masks. | | "The stack trace is enough" | Native crashes often happen far from the real cause. Ownership history matters more than the final frame. | | "I'll just add null checks" | Null checks do not fix dangling references, iterator invalidation, or races. | ## Red Flags - The crash disappears when you add logging but no root cause is identified - The only "fix" is changing optimization level - You cannot say which object owns the failing memory - The code mixes raw ownership, smart pointers, and borrowed references without clear boundaries - No regression test or sanitizer rerun happened after the fix ## Verification - [ ] A reproducible failing command or test exists - [ ] A debug-symbol build was used during diagnosis - [ ] Debugger or sanitizer output identifies the real failure class - [ ] The final fix addresses ownership, bounds, synchronization, or UB at the source - [ ] The targeted reproduction and relevant tests pass after the fix ## Tips - Prefer smaller reproductions: isolate the failing target or test before debugging the whole system - If the stack is noisy, break on the first thrown exception, failed assertion, or allocator error - Compare debug and release compile flags when behavior diverges - If the bug looks build-related after all, hand off to `fix-build-errors` ## See Also - [`systematic-debugging`](../systematic-debugging/SKILL.md) — root-cause method before tool-specific work - [`fix-build-errors`](../fix-build-errors/SKILL.md) — compile, link, and configuration failures - [`tdd-workflow`](../tdd-workflow/SKILL.md) — add regression tests after the runtime bug is fixed
Related Skills
systematic-debugging
Use when a bug is non-obvious or has resisted quick fixes — applies a 4-phase root cause analysis to find and permanently resolve the issue rather than patching symptoms
actions-debugging
Use when a GitHub Actions workflow fails — diagnose the run log, identify the root cause, and apply a targeted fix
verification-before-completion
Use before claiming any task is done — run the exact command that proves the fix works, read the output, and only then report success.
using-git-worktrees
Use when you need multiple branches checked out at once — create isolated working directories for parallel development without cloning the repository repeatedly
triage
Use when a single issue needs structured triage — classify it, reproduce if needed, request missing information, and leave a durable brief or close-out note in the tracker.
to-issues
Use when a plan, spec, or PRD must become an actionable backlog — break it into thin dependency-aware issues that each deliver a verifiable vertical slice
sprint-workflow
Use when starting a new feature, refactor, or multi-step dev task — runs the full sprint cycle (Think → Plan → Build → Review → Test → Ship → Monitor) using Copilot CLI's plan/autopilot modes.
sprint-retro
Use at the end of a sprint to run a data-driven retrospective — analyzes session history and git metrics to surface what shipped, what slowed you down, and concrete improvements.
security-audit
Use when a codebase needs a formal security audit beyond a quick scan — applies OWASP Top 10 and STRIDE threat modeling from a CSO perspective to surface systemic vulnerabilities.
release
Use when a sprint or feature is complete and ready to ship — tags the version, generates GitHub Release notes, runs rollout or smoke verification, and publishes to npm/PyPI/Docker registries.
prompt-optimizer
Use when a rough prompt, vague idea, or task description needs to become a finished copy-pasteable prompt for a chat-based LLM - rewrite it into one ready-to-send prompt with no blanks, no placeholders, and a clear output shape.
outside-voice
Use when you need an independent second opinion before, during, or after implementation — run challenge, consult, or review mode in a direct builder-to-builder voice