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 withtest_ - 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
*::AcceptSyncMessageframe fromIPC::ChannelAssociatedGroupController— always keep; this is the decisive marker for sync IPC race diagnosis - At least one
mojo::InterfaceEndpointClient::HandleValidatedMessageframe for mojo dispatch context - Generated mojo
*::StubDispatch::AcceptWithResponderframes
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 onlyStubDispatchvariant)
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
- Line 1:
-
Elision marker as the last line inside the code block.
-
Optional
### Why this stack matterssection if any of these conditions hold:- An
AcceptSyncMessageframe 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.)
- An
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 l