Commit 9dfe8bb
Fix cross-thread Dispose NRE: do not null readBase under a live reader
TestCrossThreadCloneDisposeWhileReading crashed the test host on net48 x64 with
a NullReferenceException in ReadByte at *(readBase + pos): a clone being read on
thread A was disposed on thread B, and Dispose called ReleaseCurrentChunk(),
nulling readBase while thread A sat between its `pos < currentEnd` check and its
dereference.
Dispose now only zeroes currentEnd (the fail-fast gate) and no longer nulls
readBase. There is no native reference tied to the cursor (the DrainReclaimer
owns reclamation, and keeps the view mapped until the owning root closes), so a
stale readBase is harmless: the in-flight read completes against the still-mapped
view, and the zeroed currentEnd makes every subsequent read drop to the slow path
and throw AlreadyClosed. readBase is now only ever nulled by the reading thread
itself (Seek / EnsureCurrentChunk / clone setup), never cross-thread, so the race
is structurally eliminated. The fields are GC'd with the instance.
Latent on net10 (timing-lucky in CI); manifested as a host crash on net48 x64.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent d853806 commit 9dfe8bb
1 file changed
Lines changed: 13 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
503 | 503 | | |
504 | 504 | | |
505 | 505 | | |
506 | | - | |
| 506 | + | |
507 | 507 | | |
508 | 508 | | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
509 | 521 | | |
510 | 522 | | |
511 | | - | |
512 | | - | |
513 | | - | |
514 | | - | |
515 | | - | |
516 | | - | |
517 | 523 | | |
518 | 524 | | |
519 | 525 | | |
| |||
0 commit comments