Assert failure: OBJECTREF accessed in preemptive GC mode in browser-wasm ReadyToRun runtime tests
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Build Information
Build: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581582
Build error leg or test failing: `coreclr Pri0 Runtime Tests Run R2R_CG2 browser wasm checked` — 20 of 82 Helix work items
Pull request: https://github.com/dotnet/runtime/pull/133136
The browser-wasm ReadyToRun runtime-test leg fails deterministically with a VM GC-mode assert. The failing set is identical across builds, so this is not flaky:
| Build | PR | Helix job | Result |
| --- | --- | --- | --- |
| [1580911](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1580911) | #133134 | `20b86593-abb9-407d-9cd2-35a9f3ca8784` | 82 items, 21 failed, 61 passed |
| [1581582](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581582) | #133136 | `091c9316-24e7-4e7a-964c-940d0e133fdc` | 82 items, 21 failed, 61 passed |
Same 21 work items in both: `Directed_do`, `Directed_r`, `Directed_ro`, `JIT.Generics`, `JIT.opt`, `Loader`, `LoaderClassloaderGenerics`, `Methodical_d1`, `Methodical_d2`, `Methodical_do`, `Methodical_others`, `Methodical_r1`, `Methodical_r2`, `Methodical_ro`, `Regression_1`, `Regression_3`, `Regression_6`, `Regression_PdbOnly_r_3`, `Regression_o_3`, `Regression_ro_2`, `reflection`.
This issue covers the 20 that assert in `Object::Validate`. The remaining one (`reflection`) asserts in `Thread::ObjectRefFlush` and is tracked separately, since Build Analysis matches on text and the two assert texts differ.
Note that Helix categorises these as `InfrastructureError`. They are not — they are real product asserts in a checked runtime.
## Status after #132420
#132420 (`d1a8a7d2c80`, "Route QCall exceptions through marshalling", merged 2026-09-03 20:29 UTC) fixes **part** of this, but not all of it. Both builds listed above predate that commit; the first post-fix CI run of this leg is build [1582146](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1582146) (merge commit `fcfdc22e638`, confirmed to contain `d1a8a7d2c80`), Helix job `f484f658-1090-4625-adf3-8f35293caf50`:
| | Pre-fix (1580911, 1581582) | Post-fix (1582146) |
| --- | --- | --- |
| Work items failed | 21 of 82 | **17 of 82** |
Fixed by #132420: `Directed_r`, `JIT.Generics`, `LoaderClassloaderGenerics`, `reflection`.
Still failing: `Directed_do`, `Directed_ro`, `JIT.opt`, `Loader`, `Methodical_d1`, `Methodical_d2`, `Methodical_do`, `Methodical_others`, `Methodical_r1`, `Methodical_r2`, `Methodical_ro`, `Regression_1`, `Regression_3`, `Regression_6`, `Regression_PdbOnly_r_3`, `Regression_o_3`, `Regression_ro_2`.
**This assert still reproduces post-fix.** `JIT.opt` in the post-fix build:
```
01:19:39.916 Running test: JIT/opt/ThrowHelper/NonVoidThrowHelper/NonVoidThrowHelper.dll
ASSERT FAILED
Expression: !"OBJECTREF being accessed while thread is in preemptive GC mode."
Location: /__w/1/s/src/coreclr/vm/object.cpp:506
Function: Validate
Process: 42
Frame (InterpreterFrame): 0x4fe8b8
```
So this issue stays open. Note the innermost frame here is `InterpreterFrame`, whereas the pre-fix `JIT.Generics` occurrence showed `DynamicHelperFrame` — the assert is reachable from more than one path, and #132420 addressed only some of them.
Caveat for whoever picks this up: the remaining 17 are **not** all this shape. `Methodical_d1` has no `Expression:` line in its post-fix log at all, so at least some of the residue is a different failure that still needs triage.
## Relationship to existing issues
This is **not** a new bug. It is the same underlying defect as #131925, and #132022 (closed as a duplicate of #131925) already documented a root cause: a full-framework R2R generic dictionary lookup leaves the thread in preemptive GC mode. The generics-heavy work items are exactly the ones failing, which is consistent — interpreted generic code resolves dictionary lookups inside the VM and never takes the managed QCall path.
A separate issue is filed rather than reusing #131925 because **#131925 no longer matches these failures**:
- Its match block is verbatim text specific to `Loader/ContextualReflection/ContextualReflection.dll`.
- That test was disabled on browser-wasm by #132491 / #132567, so #131925 now reports `24-Hour: 0 | 7-Day: 0` hits and is effectively dormant.
- Consequently Build Analysis reports `knownIssues: []` for the builds above, and every affected PR sees an unexplained red `runtime (Build Monitor Helix Jobs)` check.
This issue exists so those PRs can see the failure as known. Consolidate into #131925 if a maintainer prefers.
## Error Details
```
19:52:48.818 Running test: global::JitTest_Generics_Conversions_Reference_GenToGen01.Test_GenToGen01.TestEntryPoint()
ASSERT FAILED
Expression: !"OBJECTREF being accessed while thread is in preemptive GC mode."
Location: /__w/1/s/src/coreclr/vm/object.cpp:506
Function: Validate
Process: 42
Frame (DynamicHelperFrame): 0x4fe8c8
Skipping 0x4fe8c8
Frame (PrestubMethodFrame): 0x4febec
Skipping 0x4febec
Frame (PrestubMethodFrame): 0x4fef2c
Skipping 0x4fef2c
Frame (PrestubMethodFrame): 0x4ff28c
node:internal/process/promises:392
new UnhandledPromiseRejection(reason);
^
UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Debugger not attached".
Node.js v23.11.1
Expected: 100
Actual: 1
END EXECUTION - FAILED
```
The innermost frame varies by work item — `DynamicHelperFrame` in `JIT.Generics`, `InterpreterFrame` in `JIT.opt` — so it is deliberately excluded from the match block below.
## Error Message
```json
{
"ErrorMessage": [
"Expression: !\"OBJECTREF being accessed while thread is in preemptive GC mode.\"",
"Location: /__w/1/s/src/coreclr/vm/object.cpp:506",
"Function: Validate",
"Process: 42"
],
"ErrorPattern": "",
"BuildRetry": false,
"ExcludeConsoleLog": false
}
```
### Why the match block is scoped this way
This uses the **array form**: each element matches one line, in order, with arbitrary lines allowed between them.
Two earlier revisions of this issue were wrong, recorded here so the reasoning is auditable:
1. A regex on the bare assert expression. Too broad — `!"OBJECTREF being accessed while thread is in preemptive GC mode."` is a single platform-neutral assert site in `Object::Validate`, and `thread->PreemptiveGCDisabled()` appears at 26 assert sites across the VM. Either would have matched unrelated failures on any platform and silently marked them known, which is worse than having no KBE.
2. A single `ErrorMessage` string with embedded newlines. Build Analysis does not strip newlines and expects one line per signature, so a concatenated block would have matched nothing.
The four elements together scope the match to this failure: the exact assert text, the exact source location, the asserting function, and `Process: 42` — emscripten's fixed PID, which native platforms do not report. That last element is what keeps the match on browser-wasm rather than any platform hitting the same assert.
All four elements were verified verbatim against the `JIT.Generics` console log for Helix job `091c9316-24e7-4e7a-964c-940d0e133fdc`. The innermost frame is deliberately excluded because it varies by work item — `DynamicHelperFrame` in `JIT.Generics`, `InterpreterFrame` in `JIT.opt`.
Match-block verification
Every element was checked verbatim against the failing Helix console log for the job cited above.
The element set (`Expression:` / `Location:` / `Function:` / `Process:`) mirrors the block in #131925, which matched this same assert 277 times in a month — evidence that these lines are present in the artifact Build Analysis matches against. #131925 stopped matching because its block additionally pins `object.cpp:514` (this build reports `:506`) and text specific to `Loader/ContextualReflection`, whose test has since been disabled on browser-wasm.
Outstanding: I have not yet observed a Build Analysis run attribute an occurrence to this issue, so the match is reasoned rather than demonstrated. If it does not pick up, the likely cause is that these merged-runner work items abort without publishing a test result for Build Analysis to attach to, in which case the fallback is a test-disable change rather than a KBE.
> [!NOTE]
> This issue was authored with GitHub Copilot.
### Report
|Build|Repository|Test|Pull Request|
|---|---|---|---|
|[1588519](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1588519)|dotnet/runtime|[JIT/opt/Vectorization/UnrollEqualsStartsWith/UnrollEqualsStartsWith.cmd](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1588519&view=ms.vss-test-web.build-test-results-tab&runId=43844548&resultId=103726)|dotnet/runtime#133463|
|[1581766](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581766)|dotnet/runtime|[JIT/interpreter/InterpreterTester/InterpreterTester.cmd](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581766&view=ms.vss-test-web.build-test-results-tab&runId=43635218&resultId=100906)|dotnet/runtime#130805|
|[1581747](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581747)|dotnet/runtime|[JIT/interpreter/InterpreterTester/InterpreterTester.cmd](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581747&view=ms.vss-test-web.build-test-results-tab&runId=43634764&resultId=100491)||
|[1581677](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581677)|dotnet/runtime|[JIT/interpreter/InterpreterTester/InterpreterTester.cmd](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581677&view=ms.vss-test-web.build-test-results-tab&runId=43633676&resultId=100760)|dotnet/runtime#133115|
|[1581582](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581582)|dotnet/runtime|[JIT/interpreter/InterpreterTester/InterpreterTester.cmd](https://dev.azure.com/dnceng-public/public/_build/results?buildId=1581582&view=ms.vss-test-web.build-test-results-tab&runId=43631840&resultId=100878)|dotnet/runtime#133136|
#### Summary
|24-Hour Hit Count|7-Day Hit Count|1-Month Count|
|---|---|---|
|0|1|5|
Contributor guide
Assessment
This issue has not been assessed yet.