Fix crash on invalid-UTF-8/truncated profiler output during demangling - #466
Open
JakkuSakura wants to merge 1 commit into
Open
Fix crash on invalid-UTF-8/truncated profiler output during demangling#466JakkuSakura wants to merge 1 commit into
JakkuSakura wants to merge 1 commit into
Conversation
Profiler output (perf script, dtrace, xctrace) is not guaranteed to be valid UTF-8 or well-formed as a whole - e.g. a garbled symbol name (reported in flamegraph-rs#403, on Debian/perf, specifically with libssl-linked binaries), or output truncated mid multi-byte sequence/mid-tag by an interrupted profiler. Demangling assumed the whole buffer was valid UTF-8 and crashed hard on the first bad byte instead of degrading gracefully. This is a platform-agnostic problem, so it gets one fix used identically everywhere rather than a per-platform workaround: - demangle_bytes is a byte-level reimplementation of rustc_demangle's own line-scanning algorithm. Rust's mangling grammar (_ZN.../_R... plus [A-Za-z0-9_.$]*) is pure ASCII, so demangling never actually needs the whole buffer to be UTF-8 - only the matched candidate substrings do, and those are always ASCII by construction. Every other byte passes through completely unmodified, wherever it occurs, with no crash and no data loss (unlike a lossy re-encode, which would corrupt any legitimate non-UTF-8 bytes elsewhere in the buffer too). The scan is a single linear pass over the input (gating on the cheap '_' byte before the short prefix comparison), matching the algorithmic complexity of rustc_demangle's own str::find-based scan rather than a naive O(n*m) substring search - verified at ~45ms for an 81MB buffer densely packed with underscores. - This single function is used unconditionally on every platform: on Linux/dtrace it demangles the raw profiler text directly, and on macOS's xctrace path it demangles each XML attribute value in place (replacing that path's separate from_utf8_lossy-based demangling). - xctrace's XML tokenizer can additionally hard-error on truncated/ malformed input (e.g. a tag cut off mid-write), which is the same underlying problem surfacing as a different symptom. Fixed the same way: treat that as an early end of stream and keep whatever was parsed before the truncation, instead of failing the whole run. Fixes flamegraph-rs#403. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Profiler output (
perf script, dtrace, xctrace) is not guaranteed to be valid UTF-8 or well-formed as a whole - e.g. a garbled symbol name (as reported in #403, on Debian/perf, specifically with libssl-linked binaries), or output truncated mid multi-byte sequence/mid-tag by an interrupted profiler run. Demangling assumed the whole buffer was valid UTF-8 and crashed hard on the first bad byte instead of degrading gracefully.This is a platform-agnostic problem, so it gets one fix used identically on every platform rather than a per-platform workaround:
demangle_bytesis a byte-level reimplementation ofrustc_demangle's own line-scanning algorithm. Rust's mangling grammar (_ZN.../_R...plus[A-Za-z0-9_.$]*) is pure ASCII, so demangling never actually needs the whole buffer to be UTF-8 - only the matched candidate substrings do, and those are always ASCII by construction. Every other byte passes through completely unmodified, wherever it occurs, with no crash and no data loss (unlike a lossy re-encode, which would corrupt any legitimate non-UTF-8 bytes elsewhere in the buffer too). The scan is a single linear pass over the input (gating on the cheap_byte before the short prefix comparison), matching the algorithmic complexity ofrustc_demangle's ownstr::find-based scan rather than a naiveO(n*m)substring search - verified at ~45ms for an 81MB buffer densely packed with underscores.from_utf8_lossy-based demangling).Fixes #403.
Test plan
cargo test --libpasses onaarch64-apple-darwinandcargo check/clippypass onx86_64-unknown-linux-gnu(cross-checked; no Linux perf environment available for a full end-to-end run)rustc_demangle::demangle_streamerrors (stream did not contain valid UTF-8) on the same inputdemangle_bytessucceeds oncargo fmt/clippyclean on both targets🤖 Generated with Claude Code