Uh oh!
There was an error while loading. Please reload this page.
[wasm] Fix R2R stackwalk for inline P/Invoke frames and composite-image RVA base - #131243
Conversation
…ge RVA base Two wasm-only stackwalk correctness fixes, needed once R2R-compiled managed code participates in a stackwalk (exception unwind, GetCallersAssembly, Assembly.Load): 1. Inline-P/Invoke sentinel resolution (stackwalk.cpp, frames.h, helpers.cpp): An R2R inline P/Invoke frame carries the sentinel return address INLINED_PINVOKE_FROM_R2R (== 1) instead of a real native address; the real caller virtual IP is derived from m_pCallSiteSP. StackFrameIterator::NextRaw fed that sentinel straight to ProcessIp, which cannot recognize it as managed code, so the same active frame repeated forever. Resolve the sentinel to the caller virtual IP via GetWasmVirtualIPFromStackPointer before ProcessIp, failing the walk (SWA_FAILED) if the lookup returns null. The sentinel constant is moved from a helpers.cpp #define into frames.h so the stack walker can reference it. 2. Composite R2R image RVA base (codeman.inl): JitTokenToModuleRVABase resolved wasm virtual-IP ranges against the IL module base (GetModuleBaseAddress()), which is wrong for a composite R2R (WbIL) image. Use the R2R image base (ReadyToRunInfo()->GetImage()->GetBase()) so unwind-frame RVAs decode against the correct composite base. Verified: WASI CoreCLR build (clr -os wasi -c Release) 0W/0E; validated end-to-end against minimal Assembly.Load / GetExecutingAssembly R2R repros that previously looped forever in StackFrameIterator. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
Tagging subscribers to this area: @agocke |
There was a problem hiding this comment.
Pull request overview
This PR makes two WebAssembly-only correctness fixes for ReadyToRun (R2R) stack walking: (1) properly handling the sentinel “return address” used by inline P/Invoke frames in R2R, and (2) using the correct image base when mapping unwind RVAs for composite R2R images.
Changes:
- Resolve the wasm R2R inline-P/Invoke sentinel return address to a real virtual IP before calling
ProcessIpduring stack walking. - Move the sentinel constant to a typed
static constexprinframes.hso it’s accessible to stack-walk code. - Fix wasm
JitTokenToModuleRVABaseto use the R2R image base (not the IL module base) forRANGE_SECTION_VIRTUALIPsections.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/coreclr/vm/wasm/helpers.cpp | Removes the local macro sentinel definition; continues using the sentinel for active inline P/Invoke frames. |
| src/coreclr/vm/stackwalk.cpp | Adds wasm-specific handling to translate the inline P/Invoke sentinel to a virtual IP prior to ProcessIp. |
| src/coreclr/vm/frames.h | Introduces a typed sentinel constant and declares GetWasmVirtualIPFromStackPointer for wasm. |
| src/coreclr/vm/codeman.inl | Updates wasm virtual-IP RVA base resolution to use the R2R image base address. |
Uh oh!
There was an error while loading. Please reload this page.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
lewing
commented
Jul 23, 2026
/ba-g native-aot infra failures are not related |
Uh oh!
There was an error while loading. Please reload this page.
…ge RVA base (dotnet#131243) ## Summary Two wasm-only R2R stackwalk correctness fixes, needed once R2R-compiled managed code participates in a stackwalk (exception unwind, `GetCallersAssembly`, `Assembly.Load`, `GetExecutingAssembly`, …). ### 1. Inline P/Invoke sentinel resolution (`stackwalk.cpp`, `frames.h`, `helpers.cpp`) An R2R inline P/Invoke `InlinedCallFrame` carries the sentinel return address `INLINED_PINVOKE_FROM_R2R` (== 1) instead of a real native address; the real caller virtual IP is derived from `m_pCallSiteSP` (this infrastructure — the sentinel assignment and `InlinedCallFrame::UpdateRegDisplay_Impl` — already exists on `main`). But `StackFrameIterator::NextRaw` fed that sentinel straight to `ProcessIp`, which cannot recognize it as managed code, so the same active frame repeated forever — an infinite loop in any stackwalk that crosses an R2R inline-P/Invoke frame. Resolve the sentinel to the caller virtual IP via `GetWasmVirtualIPFromStackPointer` before `ProcessIp`, failing the walk (`SWA_FAILED`) if the lookup returns null. The sentinel constant moves from a `helpers.cpp` `#define` to a typed `static constexpr` in `frames.h` so the stack walker can reference it (existing `helpers.cpp` uses are unchanged semantically). ### 2. Composite R2R image RVA base (`codeman.inl`) `JitTokenToModuleRVABase` resolved wasm virtual-IP ranges against the IL module base (`GetModuleBaseAddress()`), which is wrong for a composite R2R (WbIL) image — unwind-frame RVAs decoded against the wrong base. Use the R2R image base (`ReadyToRunInfo()->GetImage()->GetBase()`), correct for both composite and standalone R2R. ## Validation - WASI CoreCLR build (`clr -os wasi -c Release`): 0W/0E; `stackwalk.cpp`/`helpers.cpp` objects recompile clean. - Validated end-to-end against minimal `Assembly.Load` / `GetExecutingAssembly` R2R repros that previously looped forever in `StackFrameIterator`. > [!NOTE] > This PR was authored with the assistance of GitHub Copilot. --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: 2902374a-f352-4c46-bcec-8a35c97733ae
Summary
Two wasm-only R2R stackwalk correctness fixes, needed once R2R-compiled managed code participates in a stackwalk (exception unwind,
GetCallersAssembly,Assembly.Load,GetExecutingAssembly, …).1. Inline P/Invoke sentinel resolution (
stackwalk.cpp,frames.h,helpers.cpp)An R2R inline P/Invoke
InlinedCallFramecarries the sentinel return addressINLINED_PINVOKE_FROM_R2R(== 1) instead of a real native address; the real caller virtual IP is derived fromm_pCallSiteSP(this infrastructure — the sentinel assignment andInlinedCallFrame::UpdateRegDisplay_Impl— already exists onmain). ButStackFrameIterator::NextRawfed that sentinel straight toProcessIp, which cannot recognize it as managed code, so the same active frame repeated forever — an infinite loop in any stackwalk that crosses an R2R inline-P/Invoke frame.Resolve the sentinel to the caller virtual IP via
GetWasmVirtualIPFromStackPointerbeforeProcessIp, failing the walk (SWA_FAILED) if the lookup returns null. The sentinel constant moves from ahelpers.cpp#defineto a typedstatic constexprinframes.hso the stack walker can reference it (existinghelpers.cppuses are unchanged semantically).2. Composite R2R image RVA base (
codeman.inl)JitTokenToModuleRVABaseresolved wasm virtual-IP ranges against the IL module base (GetModuleBaseAddress()), which is wrong for a composite R2R (WbIL) image — unwind-frame RVAs decoded against the wrong base. Use the R2R image base (ReadyToRunInfo()->GetImage()->GetBase()), correct for both composite and standalone R2R.Validation
clr -os wasi -c Release): 0W/0E;stackwalk.cpp/helpers.cppobjects recompile clean.Assembly.Load/GetExecutingAssemblyR2R repros that previously looped forever inStackFrameIterator.Note
This PR was authored with the assistance of GitHub Copilot.