andyames-a11y wrote: Closing out the deeper dive from earlier this session (tracing through our actual production code with some added `clang_analyzer_dump` calls), briefly, then a new finding that I think is more actionable than that whole thread.
Wrapping up the "why does a pointer get reinterpreted" investigation: traced the real (non-repro) crash and confirmed there's no cast anywhere in the source. The `void*`-rooted region comes from a custom allocator's `Allocate()`, which isn't resolving to a primitive the analyzer specifically recognizes (confirmed by comparing region kinds: a trivial allocator that forwards directly to ::operator new gets HeapSymRegion and is even correctly leak-tracked; ours gets a plain, untracked SymRegion, same as a fully opaque/undefined allocation function). So I'd revise my earlier "custom vs std" framing — it's more precisely "does the allocation resolve to something the analyzer recognizes," not "custom code is inherently disadvantaged." Genuinely unsure why our allocator doesn't resolve cleanly; didn't chase that further. New finding, and I think this one's worth your attention: our repro (the Span/Decoder one in the PR's regression test) and your reduced one trigger this via different mechanisms. Yours needs an explicit int v = (int)(long)ptr(); — a visibly deliberate cast. Ours has no cast anywhere. Added `clang_analyzer_dump` calls to see where the pointer-flavored value comes from in ours: https://godbolt.org/ ``` clang_analyzer_dump(inPtr); // &buffer clang_analyzer_dump(*inPtr); // lazyCompoundVal{...,buffer} scratch[0] = *inPtr; clang_analyzer_dump(scratch[0]); // &SymRegion{conj_$1{int *, ...}} [as 32 bit integer] ``` buffer is uninitialized (`char buffer[1];`, no initializer). Dereferencing it doesn't produce a plain unconstrained scalar — it comes back as a LazyCompoundVal (normally used for whole-object copies). The pointer-typed value only appears once that gets assigned into the differently-typed scratch (`int[1]`) — that's where the analyzer conjures the `int *`-typed placeholder, with nothing resembling a cast in the source. So in ours the trigger is just: read an uninitialized array element, assign the result into a scalar of a different type. No deliberate reinterpretation needed — which might make it a more representative (and more concerning) trigger than the explicit cast, since it's the kind of thing that can happen without anyone writing anything that looks unusual. https://github.com/llvm/llvm-project/pull/210200 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
