Sanitize Crash Stack
Transform a raw symbolicated native crash stack into a paste-ready comment for issues.chromium.org, crbug.com, or a Chromium Gerrit CL description. Public trackers require module names and debug output to be free of downstream product identifiers and environment PII; enforce a consistent sanitization and trimming pipeline so every posted stack has the same shape and safety guarantees.
When This Skill Applies
Trigger on a pasted crash stack combined with any of:
- Intent to file or comment on a public bug (
crbug.com, issues.chromium.org, bugs.chromium.org)
- Intent to attach to a Gerrit CL description or review comment
- Explicit phrases like "sanitize", "scrub", "脱敏", "clean up before posting"
Skip this skill when:
- The target is a private/internal tracker and the user explicitly wants the raw stack preserved
- The stack is not symbolicated (raw addresses + pdb only) — ask the user to symbolicate first using
windbg / minidump_stackwalk / llvm-symbolizer
- The stack is already in Chromium-standard form with no downstream identifiers — in that case offer trim-only mode (Steps 4-6) and skip scrub steps
Input Handling
Locate the stack trace via:
- If invoked with a file path argument, read the file with the Read tool
- Otherwise, scan the most recent user messages for a block of lines matching native stack trace patterns (function names with
!, line numbers, source file references)
- If no stack is found, ask the user to paste one
Do not proceed without an explicit stack. Do not fabricate or reconstruct missing frames.
Pipeline
Execute the six steps in order. Record each transformation to produce the final diff summary.
Step 1: Scrub Downstream Module Names
Regex-scan for module name patterns: ^\s*(\w+)\.(dll|exe|so|dylib)!.
Collect every unique module name observed. Classify each as:
- Chromium-standard:
chrome, chrome_elf, content_shell, chromedriver, libchrome, or any module prefixed with test_
- Downstream / unknown: anything else (examples:
brave, vivaldi, opera, msedge, custom embedder names)
Replacement rules:
- Chromium-standard → preserve as-is; record "Symbols from upstream Chromium build" for the provenance line
- Downstream → replace every occurrence with
chrome.dll (or matching extension: .exe→chrome.exe, .so→libchrome.so, .dylib→libchrome.dylib); record "Module names normalized to chrome.* (symbolicated against upstream source)" for the provenance line
If multiple distinct downstream modules appear, treat as a warning and list all observed names under Safety Review for human confirmation — this may indicate a mixed-process or mis-symbolicated stack.
Step 2: Normalize Locale Tokens
Apply these substitutions before rendering:
| Source |
Replacement |
行 (CJK line marker, MSVC/WinDbg CN/JP locale) |
line |
Zeile (German) |
line |
ligne (French) |
line |
строка (Russian) |
line |
| Any other non-ASCII locale token |
Flag in Safety Review and preserve |
Debugger locale pollution is common on Windows; MSVC and WinDbg emit localized line markers depending on the developer's OS language.
Step 3: Collapse C++ Template Signatures
Apply the substitution table, in order. Earlier rules must run before later ones because later rules assume earlier cleanup already happened.
| Pattern |
Replacement |
std::__Cr::basic_string<char16_t, std::__Cr::char_traits<char16_t>, std::__Cr::allocator<char16_t>> |
std::u16string |
std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> |
std::string |
std::__Cr::unique_ptr<T, std::__Cr::default_delete<T>> |
std::unique_ptr<T> |
std::__Cr:: prefix anywhere |
(delete) |
base::internal::Invoker<...huge variadic...>::RunImpl<...> |
Elide frame entirely — boilerplate |
base::internal::DecayedFunctorTraits<...>::Invoke<...> |
Elide frame entirely — boilerplate |
Preserve these types verbatim: scoped_refptr<T>, base::WeakPtr<T>, base::OnceCallback<Sig>, base::RepeatingCallback<Sig>, raw_ptr<T>, raw_ref<T>.
Step 4: Classify Signal vs Noise Frames
Keep as signal:
- Any frame with a source path under
chrome/, components/, content/, blink/, third_party/blink/, ui/, net/, gpu/, services/, sandbox/
- Any frame whose function name matches a class or method mentioned in the current bug context
- The
*::AcceptSyncMessage frame from IPC::ChannelAssociatedGroupController — always keep; this is the decisive marker for sync IPC race diagnosis
- At least one
mojo::InterfaceEndpointClient::HandleValidatedMessage frame for mojo dispatch context
- Generated mojo
*::StubDispatch::AcceptWithResponder frames
Elide as noise, replacing the contiguous tail at the bottom of the stack with a single summary line.
For the authoritative list of noise-frame families and patterns, consult:
references/noise-frames.md — Complete Chromium boilerplate frame classification with regex patterns
The most commonly elided families:
base::internal::* (Bind/Invoke machinery)
base::TaskAnnotator::*
base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::*
base::MessagePump*::*, base::RunLoop::*
content::BrowserMainLoop::*, content::BrowserMain*, content::ContentMain*
ChromeMain, MainDllLoader::*, wWinMain, main, WinMain
- Mojo dispatch middle frames:
MessageDispatcher::Accept, HandleIncomingMessage, HandleIncomingMessageThunk::Accept
- Sibling mojo stub wrappers:
*::Stub<RawPtrImplRefTraits>::AcceptWithResponder (keep only StubDispatch variant)
Replace the elided tail with one line matching the actual boilerplate family:
[base::Bind / TaskAnnotator / MessagePumpForUI / BrowserMain — standard UI-thread dispatch, elided]
Adjust the summary if the crash is on a worker thread (mention ThreadPoolImpl::Worker instead), or on an IO thread (MessagePumpLibevent or similar).
Step 5: Render Markdown Output
Format the sanitized stack as:
Provenance paragraph (outside the code block). Adjust to reflect only the transformations that were actually performed:
Adding the browser-side crash stack for context. Symbolicated against upstream source; module names normalized to chrome.*, C++ template signatures shortened, standard UI-thread dispatch tail elided. Line numbers are from a symbolicated downstream build and may differ by a few from upstream HEAD.
Fenced code block containing the sanitized frames. Each frame occupies two lines:
- Line 1:
module.dll!<function signature> (collapsed per Step 3)
- Line 2, indented 4 spaces:
source_file.cc:line_number
Elision marker as the last line inside the code block.
Optional ### Why this stack matters section if any of these conditions hold:
- An
AcceptSyncMessage frame is present — explain the sync IPC race window in one paragraph
- The crash is inside a bound callback invoked from
TaskAnnotator — note that the failing work was posted from elsewhere, so the poster site is not directly visible
- The stack spans a known Chromium trap (re-entrancy into a destroyed object, UAF during shutdown, etc.)
Step 6: Safety Review
Scan the sanitized stack for residual risk patterns before presenting it:
| Pattern |
Action |
/Users/[^/]+/, C:\\Users\\[^\\]+\\, /home/[^/]+/ |
Flag the username — likely a symbol path leak |
\S+@\S+\.\S+ (email literal) |
Flag |
\b[a-z0-9-]+\.(corp|internal|local|intranet)\b |
Flag internal hostname |
| IPv4 / IPv6 literals |
Flag |
| Non-ASCII characters (any remaining after Step 2) |
Flag — suspicious |
| Original downstream module names (missed in Step 1) |
Flag — indicates regression in Step 1 matcher |
Do not auto-delete flagged items — list them under a ### Safety review section for human judgment. A CamelCase class name that looks like a codename may actually be a legitimate Chromium class (example: JavaScriptTabModalDialogManagerDelegateDesktop). Defer that call to the human.
Output Format
Present the final result to the user in this order:
- One-line summary of transformations performed. Example: "Scrubbed 1 downstream module (
downstream→chrome), elided 18 boilerplate frames, collapsed 4 template signatures, flagged 0 residual PII."
- Provenance paragraph matching actual transformations.
- Fenced code block with the sanitized stack.
- Optional
### Why this stack matters diagnostic observations.
### Safety review list (even if empty — print "No residual concerns detected.").
- Paste instructions — one sentence reminding the user this content is not auto-posted; manual copy into the tracker or Gerrit comment field is required, and the Preview button should be used before Submit.
Validation Checklist
Before returning the output, verify:
- Provenance paragraph matches only the transformations actually performed
- No downstream module names remain (if Step 1 scrub was applied)
- All non-ASCII characters accounted for (normalized in Step 2 or flagged in Step 6)
- Elision line accurately reflects the noise family elided (UI thread vs worker vs IO)
- Safety review section is present (empty-state message if no flags)
- At least the top signal frame (the crashing function) is preserved with original function name
- Line numbers are not modified — only module names and template signatures are transformed
Additional Resources
Reference Files
references/noise-frames.md — Authoritative list of Chromium frame families classified as noise, with regex patterns and worker-thread variants
Common Mistakes to Avoid
- Do not guess line numbers against upstream HEAD. Line numbers may differ between downstream builds and upstream; preserve the original numbers and note the possible drift in the provenance paragraph.
- Do not strip
AcceptSyncMessage. It is the decisive marker that distinguishes a sync IPC race from an async dispatch race. Reviewers use it to diagnose the race window.
- Do not auto-resolve CamelCase flags. Class names that look like product codenames may be legitimate Chromium types. Only a human can decide.
- Do not post the output directly. This skill prepares a paste-ready block; the user must manually paste and preview in the tracker.
1---2name: sanitize-stack3description: This skill should be used when the user asks to "sanitize a crash stack", "scrub a stack trace", "clean up a stack for crbug", "prepare a stack for issues.chromium.org", "prepare a stack for Gerrit", "脱敏崩溃堆栈", or pastes a native crash stack (typically Chromium or a Chromium-based embedder) and expresses intent to attach it to a public issue tracker or code review. Transforms raw symbolicated stacks into paste-ready comments by scrubbing downstream module names, normalizing locale tokens, collapsing verbose C++ template signatures, eliding Chromium boilerplate frames, and flagging residual PII for human review.4---56# Sanitize Crash Stack78Transform a raw symbolicated native crash stack into a paste-ready comment for `issues.chromium.org`, `crbug.com`, or a Chromium Gerrit CL description. Public trackers require module names and debug output to be free of downstream product identifiers and environment PII; enforce a consistent sanitization and trimming pipeline so every posted stack has the same shape and safety guarantees.910## When This Skill Applies1112Trigger on a pasted crash stack combined with any of:1314- Intent to file or comment on a public bug (`crbug.com`, `issues.chromium.org`, `bugs.chromium.org`)15- Intent to attach to a Gerrit CL description or review comment16- Explicit phrases like "sanitize", "scrub", "脱敏", "clean up before posting"1718Skip this skill when:1920- The target is a private/internal tracker and the user explicitly wants the raw stack preserved21- The stack is not symbolicated (raw addresses + pdb only) — ask the user to symbolicate first using `windbg` / `minidump_stackwalk` / `llvm-symbolizer`22- The stack is already in Chromium-standard form with no downstream identifiers — in that case offer trim-only mode (Steps 4-6) and skip scrub steps2324## Input Handling2526Locate the stack trace via:27281. If invoked with a file path argument, read the file with the Read tool292. Otherwise, scan the most recent user messages for a block of lines matching native stack trace patterns (function names with `!`, line numbers, source file references)303. If no stack is found, ask the user to paste one3132Do not proceed without an explicit stack. Do not fabricate or reconstruct missing frames.3334## Pipeline3536Execute the six steps in order. Record each transformation to produce the final diff summary.3738### Step 1: Scrub Downstream Module Names3940Regex-scan for module name patterns: `^\s*(\w+)\.(dll|exe|so|dylib)!`.4142Collect every unique module name observed. Classify each as:4344- **Chromium-standard**: `chrome`, `chrome_elf`, `content_shell`, `chromedriver`, `libchrome`, or any module prefixed with `test_`45- **Downstream / unknown**: anything else (examples: `brave`, `vivaldi`, `opera`, `msedge`, custom embedder names)4647Replacement rules:4849- Chromium-standard → preserve as-is; record "Symbols from upstream Chromium build" for the provenance line50- Downstream → replace every occurrence with `chrome.dll` (or matching extension: `.exe`→`chrome.exe`, `.so`→`libchrome.so`, `.dylib`→`libchrome.dylib`); record "Module names normalized to chrome.* (symbolicated against upstream source)" for the provenance line5152If multiple distinct downstream modules appear, treat as a warning and list all observed names under Safety Review for human confirmation — this may indicate a mixed-process or mis-symbolicated stack.5354### Step 2: Normalize Locale Tokens5556Apply these substitutions before rendering:5758| Source | Replacement |59|---|---|60| `行` (CJK line marker, MSVC/WinDbg CN/JP locale) | `line` |61| `Zeile` (German) | `line` |62| `ligne` (French) | `line` |63| `строка` (Russian) | `line` |64| Any other non-ASCII locale token | Flag in Safety Review and preserve |6566Debugger locale pollution is common on Windows; MSVC and WinDbg emit localized line markers depending on the developer's OS language.6768### Step 3: Collapse C++ Template Signatures6970Apply the substitution table, in order. Earlier rules must run before later ones because later rules assume earlier cleanup already happened.7172| Pattern | Replacement |73|---|---|74| `std::__Cr::basic_string<char16_t, std::__Cr::char_traits<char16_t>, std::__Cr::allocator<char16_t>>` | `std::u16string` |75| `std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>>` | `std::string` |76| `std::__Cr::unique_ptr<T, std::__Cr::default_delete<T>>` | `std::unique_ptr<T>` |77| `std::__Cr::` prefix anywhere | (delete) |78| `base::internal::Invoker<...huge variadic...>::RunImpl<...>` | Elide frame entirely — boilerplate |79| `base::internal::DecayedFunctorTraits<...>::Invoke<...>` | Elide frame entirely — boilerplate |8081Preserve these types verbatim: `scoped_refptr<T>`, `base::WeakPtr<T>`, `base::OnceCallback<Sig>`, `base::RepeatingCallback<Sig>`, `raw_ptr<T>`, `raw_ref<T>`.8283### Step 4: Classify Signal vs Noise Frames8485**Keep as signal:**8687- Any frame with a source path under `chrome/`, `components/`, `content/`, `blink/`, `third_party/blink/`, `ui/`, `net/`, `gpu/`, `services/`, `sandbox/`88- Any frame whose function name matches a class or method mentioned in the current bug context89- The `*::AcceptSyncMessage` frame from `IPC::ChannelAssociatedGroupController` — always keep; this is the decisive marker for sync IPC race diagnosis90- At least one `mojo::InterfaceEndpointClient::HandleValidatedMessage` frame for mojo dispatch context91- Generated mojo `*::StubDispatch::AcceptWithResponder` frames9293**Elide as noise**, replacing the contiguous tail at the bottom of the stack with a single summary line.9495For the authoritative list of noise-frame families and patterns, consult:9697- **`references/noise-frames.md`** — Complete Chromium boilerplate frame classification with regex patterns9899The most commonly elided families:100101- `base::internal::*` (Bind/Invoke machinery)102- `base::TaskAnnotator::*`103- `base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::*`104- `base::MessagePump*::*`, `base::RunLoop::*`105- `content::BrowserMainLoop::*`, `content::BrowserMain*`, `content::ContentMain*`106- `ChromeMain`, `MainDllLoader::*`, `wWinMain`, `main`, `WinMain`107- Mojo dispatch middle frames: `MessageDispatcher::Accept`, `HandleIncomingMessage`, `HandleIncomingMessageThunk::Accept`108- Sibling mojo stub wrappers: `*::Stub<RawPtrImplRefTraits>::AcceptWithResponder` (keep only `StubDispatch` variant)109110Replace the elided tail with one line matching the actual boilerplate family:111112```113[base::Bind / TaskAnnotator / MessagePumpForUI / BrowserMain — standard UI-thread dispatch, elided]114```115116Adjust the summary if the crash is on a worker thread (mention `ThreadPoolImpl::Worker` instead), or on an IO thread (`MessagePumpLibevent` or similar).117118### Step 5: Render Markdown Output119120Format the sanitized stack as:1211221. **Provenance paragraph** (outside the code block). Adjust to reflect only the transformations that were actually performed:123124 > Adding the browser-side crash stack for context. Symbolicated against upstream source; module names normalized to `chrome.*`, C++ template signatures shortened, standard UI-thread dispatch tail elided. Line numbers are from a symbolicated downstream build and may differ by a few from upstream HEAD.1251262. **Fenced code block** containing the sanitized frames. Each frame occupies two lines:127 - Line 1: `module.dll!<function signature>` (collapsed per Step 3)128 - Line 2, indented 4 spaces: `source_file.cc:line_number`1291303. **Elision marker** as the last line inside the code block.1311324. **Optional `### Why this stack matters` section** if any of these conditions hold:133 - An `AcceptSyncMessage` frame is present — explain the sync IPC race window in one paragraph134 - The crash is inside a bound callback invoked from `TaskAnnotator` — note that the failing work was posted from elsewhere, so the poster site is not directly visible135 - The stack spans a known Chromium trap (re-entrancy into a destroyed object, UAF during shutdown, etc.)136137### Step 6: Safety Review138139Scan the sanitized stack for residual risk patterns before presenting it:140141| Pattern | Action |142|---|---|143| `/Users/[^/]+/`, `C:\\Users\\[^\\]+\\`, `/home/[^/]+/` | Flag the username — likely a symbol path leak |144| `\S+@\S+\.\S+` (email literal) | Flag |145| `\b[a-z0-9-]+\.(corp\|internal\|local\|intranet)\b` | Flag internal hostname |146| IPv4 / IPv6 literals | Flag |147| Non-ASCII characters (any remaining after Step 2) | Flag — suspicious |148| Original downstream module names (missed in Step 1) | Flag — indicates regression in Step 1 matcher |149150Do not auto-delete flagged items — list them under a `### Safety review` section for human judgment. A CamelCase class name that looks like a codename may actually be a legitimate Chromium class (example: `JavaScriptTabModalDialogManagerDelegateDesktop`). Defer that call to the human.151152## Output Format153154Present the final result to the user in this order:1551561. **One-line summary** of transformations performed. Example: "Scrubbed 1 downstream module (`downstream`→`chrome`), elided 18 boilerplate frames, collapsed 4 template signatures, flagged 0 residual PII."1572. **Provenance paragraph** matching actual transformations.1583. **Fenced code block** with the sanitized stack.1594. **Optional `### Why this stack matters`** diagnostic observations.1605. **`### Safety review`** list (even if empty — print "No residual concerns detected.").1616. **Paste instructions** — one sentence reminding the user this content is not auto-posted; manual copy into the tracker or Gerrit comment field is required, and the Preview button should be used before Submit.162163## Validation Checklist164165Before returning the output, verify:166167- Provenance paragraph matches only the transformations actually performed168- No downstream module names remain (if Step 1 scrub was applied)169- All non-ASCII characters accounted for (normalized in Step 2 or flagged in Step 6)170- Elision line accurately reflects the noise family elided (UI thread vs worker vs IO)171- Safety review section is present (empty-state message if no flags)172- At least the top signal frame (the crashing function) is preserved with original function name173- Line numbers are not modified — only module names and template signatures are transformed174175## Additional Resources176177### Reference Files178179- **`references/noise-frames.md`** — Authoritative list of Chromium frame families classified as noise, with regex patterns and worker-thread variants180181## Common Mistakes to Avoid182183- **Do not guess line numbers against upstream HEAD.** Line numbers may differ between downstream builds and upstream; preserve the original numbers and note the possible drift in the provenance paragraph.184- **Do not strip `AcceptSyncMessage`.** It is the decisive marker that distinguishes a sync IPC race from an async dispatch race. Reviewers use it to diagnose the race window.185- **Do not auto-resolve CamelCase flags.** Class names that look like product codenames may be legitimate Chromium types. Only a human can decide.186- **Do not post the output directly.** This skill prepares a paste-ready block; the user must manually paste and preview in the tracker.