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

8 stars

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

$curl -o ~/.claude/skills/cpp-debugging/SKILL.md --create-dirs "https://raw.githubusercontent.com/drvoss/everything-copilot-cli/main/skills/development/cpp-debugging/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/cpp-debugging/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How cpp-debugging Compares

Feature / Agentcpp-debuggingStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

Use when a GitHub Actions workflow fails — diagnose the run log, identify the root cause, and apply a targeted fix

verification-before-completion

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

Use when you need multiple branches checked out at once — create isolated working directories for parallel development without cloning the repository repeatedly

triage

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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

8
from drvoss/everything-copilot-cli

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