Skip to content

Assert failure: OBJECTREF accessed in preemptive GC mode in browser-wasm ReadyToRun runtime tests #133219

Description

@lewing

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: #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 #133134 20b86593-abb9-407d-9cd2-35a9f3ca8784 82 items, 21 failed, 61 passed
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 (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:

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

{
  "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
1581766 dotnet/runtime JIT/interpreter/InterpreterTester/InterpreterTester.cmd #130805
1581747 dotnet/runtime JIT/interpreter/InterpreterTester/InterpreterTester.cmd
1581677 dotnet/runtime JIT/interpreter/InterpreterTester/InterpreterTester.cmd #133115
1581582 dotnet/runtime JIT/interpreter/InterpreterTester/InterpreterTester.cmd #133136

Summary

24-Hour Hit Count 7-Day Hit Count 1-Month Count
0 4 4

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Known Build ErrorUse this to report build issues in the .NET Helix tabarch-wasmWebAssembly architecturearea-VM-coreclrblocking-clean-ciBlocking PR or rolling runs of 'runtime' or 'runtime-extra-platforms'

Type

No type

Projects

  • Status
    No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions