Skip to content

Add .NET 10 compatibility support - #524

Open
Frank Shearar (frankshearar) wants to merge 24 commits into
microsoft:mainfrom
frankshearar:feature/net10-support
Open

Frank Shearar (frankshearar) wants to merge 24 commits into
microsoft:mainfrom
frankshearar:feature/net10-support

Conversation

@frankshearar

Copy link
Copy Markdown
Member

No description provided.

@frankshearar
Frank Shearar (frankshearar) force-pushed the feature/net10-support branch 2 times, most recently from 7de020b to a635b5d Compare August 25, 2026 00:11
Upgrade xUnit to 2.6.2 and the Visual Studio adapter to 2.5.4. These releases include the fix for disabled collection parallelization with synchronous reporting: xunit/visualstudio.xunit#392
Control WaitAsync completion, preserve WhenEach completion order, and separate Lock and Monitor state. Add regression coverage and align repository, probe, and pipeline SDK pins.

Copilot-Session: f70e2526-22a3-48bf-b1be-454449bca15d
Update the three IL-diff hash baselines affected by the new WaitAsync, WhenEach, and Lock/Monitor regression tests. Local .NET 10 and .NET 8 comparisons match the Windows CI output.

Copilot-Session: f70e2526-22a3-48bf-b1be-454449bca15d
Exercise locally built library and CLI packages in cross-platform sample CI. Use isolated package caches, require matching framework assets, and rewrite and test package-based probes with the installed tool.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 109deff7-3338-4d4a-ac06-6feb4b58fdaf
@akashlal

Copy link
Copy Markdown
Collaborator

There are a few additional concurrency APIs/contracts worth covering before declaring .NET 10 support. Comparing the .NET 8, 9, and 10 reference surfaces with the replacements in this PR shows these gaps (including .NET 9 additions that .NET 10 applications can use):

Area Gap Requested handling
Small-integer atomics Interlocked.Exchange and CompareExchange overloads for byte, sbyte, short, and ushort were added in .NET 9, but have no Coyote replacements. Add controlled replacements with scheduling points, consistent with the existing integer atomics, or explicitly diagnose them as unsupported. Leaving these calls native loses the exploration opportunities provided for other atomics.
Generic atomics Since .NET 9, Interlocked.Exchange<T> and CompareExchange<T> accept primitive and enum types as well as reference types. Coyote's replacements still require where T : class. Update the replacement contracts and cover primitive/enum instantiations. This is more than a missing overload: matching the existing signature can redirect a valid application call to a replacement with incompatible generic constraints.
Memory barriers .NET 10 added Volatile.ReadBarrier() and WriteBarrier(). Neither appears in the replacements or the API gate. Explicitly classify their behavior under Coyote's memory model. Native pass-through may be appropriate, but it should be a deliberate, documented decision rather than an unexamined gap.
Named wait handles .NET 10 added constructors/opening overloads using NamedWaitHandleOptions; the new EventWaitHandle constructors are absent from Coyote's creation wrappers. Audit the boundary and clearly reject unsupported cross-process synchronization. Existing name-based rejection covers some opening methods, but not these constructors. This does not require implementing cross-process model checking.

The generic Interlocked contract change also illustrates why the API audit needs to include changed constraints/semantics, not just newly named methods.

I would ask this PR to address the two atomic gaps and explicitly classify the barrier and wait-handle boundaries. I would not require modeling every new async library feature (async ZIP APIs, JSON-over-pipelines, async LINQ); those can follow the existing external-library/uncontrolled-operation policy. Similarly, the absence of wrappers for TaskCompletionSource.SetFromTask alone does not establish a scheduling defect, since its input must already be completed.

These are coverage findings from inspection, not yet reproduced runtime failures like the previously discussed WaitAsync and WaitAll cases.

@akashlal

Copy link
Copy Markdown
Collaborator

Three additional review findings, separate from the runtime API coverage gaps:

[P1] Preserve the first completion event in WaitAsync

Location: Source/Test/Rewriting/Types/Threading/Tasks/Task.cs, shared CreateWaitAsyncTask helper (around lines 389-405).

The helper chooses cancellationTask.IsCanceled ? cancellationTask : task based on the state when the helper operation runs, rather than recording which event completed the wait first. I reproduced this with a default TaskCompletionSource<int>:

using var cts = new CancellationTokenSource();
var source = new TaskCompletionSource<int>();
Task<int> wait = source.Task.WaitAsync(cts.Token);
source.SetResult(42);
cts.Cancel();
Assert.Equal(42, await wait);

Native .NET 10 returns 42; the controlled version fails with TaskCanceledException when the helper runs after both events. The shared helper affects generic and non-generic overloads, so this can produce false bugs in both.

Please record the completion/cancellation winner when the event occurs, and add a regression where source completion precedes cancellation without an intervening await.

[P1] Observe cancellation while enumerable WaitAll is blocked

Location: Source/Test/Rewriting/Types/Threading/Tasks/Task.cs, enumerable overload (around lines 724-728) and shared array implementation (around lines 736-761); TaskServices.WaitUntilAllTasksComplete.

The new overload delegates to the array implementation, whose controlled wait resumes only when all tasks complete. The cancellation check before entering the wait does not handle cancellation occurring afterward.

using var cts = new CancellationTokenSource();
var pending = new TaskCompletionSource<int>();
Task canceler = Task.Run(() => cts.Cancel());
Assert.ThrowsAny<OperationCanceledException>(() =>
    Task.WaitAll((IEnumerable<Task>)new Task[] { pending.Task }, cts.Token));
canceler.GetAwaiter().GetResult();

Native .NET 10 throws OperationCanceledException. Coyote can instead report a deadlock when the wait begins before the cancellation operation executes, because the incomplete task prevents the wait predicate from becoming true.

The underlying array-path limitation predates this PR, but the newly supported enumerable overload exposes it. Please include cancellation in the controlled wake-up condition and cover cancellation after the wait starts, not just an already-canceled token.

[P2] Discover the runtime API surface independently of its classifications

Location: Tests/Tests.Rewriting/Types/RuntimeApiDiffGateTests.cs, GetRuntimeMembers (around lines 133-195).

GetRuntimeMembers() manually lists the signatures to inspect, and the supported/unsupported classifications are derived from that same list. A newly added runtime overload never enters the input, so the gate remains green without requiring a classification.

The synthetic added-method test checks the classifier by manually appending a fabricated signature; it does not check runtime discovery. Even the WhenEach and span-based task overloads supported by this PR are absent from the list.

Please discover the explicitly audited runtime types/API families independently, then compare that surface against explicit supported/unsupported classifications. A regression should demonstrate that an unclassified member found through the discovery path fails the gate. This need not classify the entire BCL.

The two P1 issues above were reproduced against native .NET 10; the P2 finding is established by inspection of the gate.

Akash Lal (akashlal) and others added 15 commits October 9, 2026 15:38
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 109deff7-3338-4d4a-ac06-6feb4b58fdaf
Integrates upstream Monitor.SynchronizedBlock.ResetCache (microsoft#510) and Dependabot config (microsoft#520). [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/prepare]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
Snapshot of the approved plan (SHA256 6A284A21C7E09E4EC8AC4017D2AE05BB5817EA510F43FF458EFD2193F2C65117) guiding the seven review fixes. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/prepare]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
The shared controlled WaitAsync helper chose the cancellation task whenever the wait token was canceled by the time the helper ran, so a source that completed before the token was canceled was reported as canceled. The wait cancellation registration now samples the source state when the token is canceled and does not cancel the wait if a source that delivers its outcome synchronously has already completed. Sources that run continuations asynchronously keep racing a later cancellation, as the uncontrolled runtime does. Fast paths, token identity, registration cleanup, the finite-timeout model and the fuzzing/native paths are unchanged.

Adds a native oracle and regressions for result, fault and source cancellation in both event orders, for generic and non-generic waits, with default and asynchronous source continuations, plus the reviewer's TaskCompletionSource reproducer in systematic, rewriting and fuzzing tests. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/fix-waitasync]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
The controlled array WaitAll, which the enumerable overload delegates to, checked the token only before pausing and resumed only when every task completed, so a cancellation requested after the wait started was reported as a deadlock. The controlled wait now also resumes when a cancelable token is canceled. The first of task completion and cancellation is recorded when the token is canceled, matching the uncontrolled wait: completion first returns or propagates task faults, a requested cancellation still takes precedence over canceled tasks unless a task faulted, and cancellation first throws for the wait token without completing pending tasks. Callers without a cancelable token, validation, empty inputs, uncontrolled-task detection, the timeout policy and fuzzing are unchanged.

Adds a native oracle and regressions for array and enumerable overloads where the wait starts before cancellation, for result, fault and source cancellation in both event orders, an already-canceled token with completed and empty inputs, controlled completion with a cancelable token, and a genuine deadlock with a never-canceled token. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/fix-waitall]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
On .NET 9 and later, the runtime adds Interlocked.Exchange and CompareExchange for byte, sbyte, short and ushort, and accepts primitive and enum type arguments for the generic overloads. The small-integer calls were passed through without a scheduling point, and explicit primitive or enum generic calls were redirected to the class-constrained replacement, which produced unverifiable IL. The replacement now adds the eight small-integer overloads and removes the class constraint from the generic overloads on .NET 9 and later, exploring an interleaving and then delegating to the runtime so that it keeps its own type validation. Older targets keep the reference-only contract and do not reference the newer APIs.

Tests cover old-value returns and successful and failed comparisons for all four types, lost updates that are found only through the new scheduling points, explicit generic calls for a reference type, a primitive and enums of different widths against the native outcome, native NotSupportedException parity for an unsupported value type, and the rewritten IL of all eight overloads and the explicit generic calls. The API gate now identifies generic parameters by position and arity, and rejects replacements with stricter generic constraints. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/fix-atomics]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
… test

When a blocked uncontrolled WaitAll observes a canceled task and the wait token is canceled right after, it reports either the requested cancellation or an aggregate TaskCanceledException, depending on when the blocked wait wakes up. The native oracle assertion required the former and failed intermittently. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/classify-barriers]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
Systematic testing executes one controlled operation at a time and does not explore weak-memory reorderings. Volatile reads and writes and Interlocked operations add a scheduling point before their memory access, while barriers that do not access memory, such as Thread.MemoryBarrier and Interlocked.MemoryBarrier, have no replacement and are invoked natively. The .NET 10 Volatile.ReadBarrier and WriteBarrier follow the same policy: they never block, so they are not uncontrolled synchronization, and they only constrain reorderings that Coyote does not model.

Documents the memory-ordering boundary in the binary rewriting docs and the .NET 10 compatibility assessment, classifies both barriers as pass-through with a reason in the runtime API gate, and adds tests that the rewritten IL keeps the barriers as runtime calls next to controlled volatile accesses, that volatile accesses are scheduling points, and that barriers are not. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/classify-barriers]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
An earlier edit in this remediation rewrote the file without its original UTF-8 byte order mark. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/named-handles]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
The name-bearing EventWaitHandle constructors created the native named system event and registered it as a process-local controlled resource, although other processes can share a named event, and the .NET 10 constructors that take NamedWaitHandleOptions were not intercepted at all. During systematic testing, every EventWaitHandle constructor with a non-empty name now reports a bug and throws NotSupportedException before the system event is created or opened. A null or empty name natively creates an unnamed, unshared event, so it stays controlled, including through the new NamedWaitHandleOptions overloads. Opening methods and Mutex and Semaphore stay reported as uncontrolled invocations, and native behavior outside interleaving testing is unchanged.

Tests cover the native null and empty name contract, rejection of all four name-bearing constructors with a check that the named event does not exist afterwards on Windows, controlled unnamed events through every overload, opening methods including NamedWaitHandleOptions, and Mutex and Semaphore NamedWaitHandleOptions constructors. The API gate classifies the NamedWaitHandleOptions opening methods with a reason, and the binary rewriting docs and .NET 10 assessment document the boundary. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/named-handles]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
…cations

The runtime API gate inspected a hand-written list of signatures and derived its classifications from the same list, so a new runtime overload never entered the gate. The gate now discovers, through reflection, every public method, accessor and constructor of explicitly audited families: Task wait, join, delay and RunSynchronously, Task<T>.WaitAsync, Monitor, SemaphoreSlim, Interlocked Increment, Exchange and CompareExchange, Volatile barriers, WaitHandle.WaitOne, Thread.Sleep, Lock, and EventWaitHandle, Mutex and Semaphore constructors and openers. Signatures capture constructor, static or instance form, generic arity and constraints, ref, out and in parameters, and return type. Every discovered member needs exactly one framework-specific classification: controlled with a compatible replacement, rejected by the uncontrolled invocation rewriting pass with a reason, or passed through with a reason. Unclassified, missing-replacement, overlapping, stale and empty-reason classifications fail the gate on .NET 10, 8, 6 and .NET Framework 4.6.2.

Discovery found three gaps, now fixed: Monitor.TryEnter(object, int) and Task.Wait(TimeSpan, CancellationToken) had no controlled replacement and blocked natively, and the .NET Framework EventWaitHandle constructor that takes EventWaitHandleSecurity created a named event without being reported. Adds a fixture family with an extra overload run through the real discovery path, stale, overlap, reason and rewriting-mismatch regressions, and rewriting tests for the two new replacements. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/api-gate]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
Updates the expected IL diff hashes of Tests.Rewriting and Tests.BugFinding on .NET 10 and 8 for the tests added by the review remediation. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/api-gate]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
Describes how controlled Task.WaitAsync and Task.WaitAll order completion and cancellation in the binary rewriting docs, and appends a dated addendum to the .NET 10 compatibility assessment that summarizes the seven review outcomes while keeping the original assessment as historical evidence. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/validate]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
The packages ship net10.0, net8.0, net6.0 and netstandard2.0 assets, so programs that target .NET 9 resolve the net8.0 build, which has neither the small-integer Interlocked replacements nor the relaxed generic contract. The assessment said both applied on .NET 9 and later. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/review-diff]

Copilot-Session: 65bb6a21-b626-4e36-b214-355fba112613
On Linux and macOS the .NET runtime rejects an EventWaitHandle created with an empty name with a PlatformNotSupportedException, whereas on Windows an empty name creates an unnamed event. The controlled constructors already pass empty names to the runtime, so they keep that native behavior, but the tests and docs assumed the Windows contract everywhere, which failed the Ubuntu CI job. The native oracle and the unnamed event tests now assert the platform-specific native contract, including that the non-Windows failure is the runtime's own exception rather than a Coyote rejection, and the docs describe both platforms. Refreshes the Tests.Rewriting IL diff hashes for the updated tests. [cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/ci-green]

Copilot-Session: 71190617-9b6c-4fe4-b5f6-7af5e3190a95
@frankshearar

Copy link
Copy Markdown
Member Author

Frank the Clank says: the review findings from Akash Lal (@akashlal) in the API coverage comment and the correctness and gate comment are addressed in the commits below. Each was first reproduced as a failing test against the previous code where applicable. PR head is now df9ac266. Coyote CI run 38024569802 passes on that head: build/test and samples on Windows, Ubuntu and macOS, plus license/cla.

# Finding Change Commit
1 [P1] WaitAsync first event Cancellation no longer replaces a source outcome that was already delivered. Your SetResult(42), Cancel() reproducer now returns 42, and the non-generic form completes. Sources with RunContinuationsAsynchronously can still lose to a later cancellation, as native .NET does. Tests compare controlled results with native .NET for result/fault/source-cancel, in both orders, for both task forms. a7245785
2 [P1] Blocked WaitAll cancellation The controlled wait wakes on cancellation as well as completion. It throws for the wait token and leaves pending tasks incomplete. Tests start the wait before cancelling (array and IEnumerable overloads) and compare completion-versus-cancellation ordering with native .NET. Waits with a token that is never cancelled still report deadlocks. ea5dcf16, 5dcbb54b
3 Small-integer atomics Exchange/CompareExchange for byte/sbyte/short/ushort are controlled scheduling points on .NET 9+. Tests include lost-update contention that is only found through those points. 1266433d
4 Generic atomics On .NET 9+ the generic replacements drop where T : class and delegate type validation to the runtime. Explicit <object>/<int>/byte- and long-enum calls match native .NET, and <DateTime> throws the same NotSupportedException. Older targets keep the class constraint. Before this fix, ilverify reported unsatisfied constraints for these calls. 1266433d
5 Volatile barriers These are deliberate native pass-through with no scheduling point, the same as Thread/Interlocked.MemoryBarrier. Coyote does not explore weak-memory reorderings. Documented in binary-rewriting.md and the assessment; the API gate classifies both with a reason. a99851a0
6 Named wait handles During systematic testing, every name-bearing EventWaitHandle constructor, including the NamedWaitHandleOptions overloads, is rejected before any OS event is created or opened. A null name, and an empty name on Windows, stay controlled; on Unix the runtime itself rejects an empty name. Opening methods, Mutex and Semaphore remain reported as uncontrolled. Cross-process model checking is out of scope. 17e37708, df9ac266
7 [P2] Independent API discovery The gate now discovers the audited families by reflection, independently of their classifications. Signatures include constructors, generic arity and constraints, and ref/out. Each member needs exactly one classification per framework: controlled, rejected (with reason) or pass-through (with reason). Unclassified, missing, overlapping and stale entries fail. A fixture with an extra overload fails through the real discovery path, and WhenEach and the span overloads are discovered. Discovery found and fixed Monitor.TryEnter(object, int), Task.Wait(TimeSpan, CancellationToken) and the .NET Framework EventWaitHandleSecurity constructor. d075d2a7

Also included: a merge of origin/main, which keeps Monitor.SynchronizedBlock.ResetCache (#510); refreshed rewriting snapshots; and a dated addendum to NET10-COMPATIBILITY-ASSESSMENT.md. Locally on Windows, Scripts/run-tests.ps1 -ci, the compatibility matrix and the net10.0/net8.0 package smoke tests passed.

Not changed, per your guidance: async ZIP, JSON-over-pipelines and async LINQ stay under the existing external-library policy, and no SetFromTask wrappers were added. This needs your re-review; I am not marking anything as approved.

[cdb:ri_mv1nmbnv_0000005_17bb2b0c07a4/respond]

@akashlal

Copy link
Copy Markdown
Collaborator

Thanks for addressing the earlier review findings. I re-reviewed head df9ac266e07e5d62029b95fe7c80410d5b9338e6. The earlier WaitAsync ordering, WaitAll cancellation, atomic-API coverage, named-event boundary, and independent API-discovery findings now appear addressed. I would still request changes for two correctness issues in overloads added during remediation:

  1. [P1] Cancelable Task.Wait(TimeSpan, token) reports false deadlocks — Task.cs:941–949. The new wrapper delegates to a helper that pauses until the task completes, ignoring cancellation while paused. Both an already-canceled token and cancellation during the wait throw OperationCanceledException natively but report deadlock under Coyote. I reproduced and replayed both on the current head. The fix needs to handle cancellation before pausing and wake a blocked wait when cancellation occurs.

  2. [P1] Monitor.TryEnter(obj, 0) blocks instead of returning false — Monitor.cs:184–190. The new overload unconditionally calls blocking SynchronizedBlock.Lock. With a parent holding the monitor and waiting for a worker's zero-timeout attempt, native execution returns false and finishes; Coyote reports deadlock. This also reproduces and replays on the current head. Zero-timeout attempts should use the existing nonblocking TryLock helper.

CI is green, but these two newly intercepted overloads still change program behavior. Please add regression coverage for the canceled waits and the contended zero-timeout monitor attempt alongside the fixes.

@pdeligia

Copy link
Copy Markdown
Member

Copilot resolve the merge conflicts in this pull request

Preserve framework-specific IL snapshots while incorporating the constructor opcode fix. Existing rewriting IL is unchanged outside the added constructor regression types on both target frameworks.

Copilot-Session: 3447f3e5-9328-4334-8f18-0223764709a5
Wake controlled task waits when their token is canceled, without overriding native completed-task and exception behavior. Use TryLock for zero-timeout and untimed TryEnter overloads instead of blocking the caller.

Cover pre-canceled and blocked waits across all cancellation overloads, genuine deadlock detection, completed tasks, and contended and reentrant monitor attempts. Refresh only reviewed BugFinding snapshots.

Copilot-Session: 3447f3e5-9328-4334-8f18-0223764709a5
Copilot AI balanced review requested due to automatic review settings October 23, 2026 17:48
@frankshearar

Copy link
Copy Markdown
Member Author

Frank the Clank says: the two follow-up correctness findings in the October 14 review are addressed in bdfe9c83. Upstream main, including the constructor fix from #529, is merged in cc1a28b4, resolving the merge conflict.

Finding Change and regression coverage
Cancelable Task.Wait(TimeSpan, token) reports false deadlocks The shared controlled-wait helper skips pausing for an already-canceled wait token and wakes on either task completion or wait cancellation. The final native Task.Wait still determines completion and exception behavior. Regressions cover cancellation before and during the wait for the TimeSpan, integer-timeout, and token-only overloads; check the cancellation token and that the pending task remains incomplete; preserve successful completion with an already-canceled wait token; and retain/replay genuine deadlocks when the token is never canceled.
Monitor.TryEnter(obj, 0) blocks Zero-timeout attempts use SynchronizedBlock.TryLock, including the corresponding TimeSpan/ref-bool overloads. Untimed nonblocking overloads use the same helper. Regressions cover a parent holding the monitor while joining a worker's failed acquisition, plus uncontended/reentrant acquisition and balanced releases, across all six overload forms with lock-access race checking enabled. Positive-timeout modeling is unchanged.
Merge conflict Kept PR524's framework-specific snapshot gate and incorporated the constructor regressions from main. Rebuilt the original PR head to reproduce its existing hashes, then compared generated IL: outside the edited TaskWaitTests/MonitorTests types and the newly merged constructor test types, the IL is unchanged on both frameworks. Only the corresponding reviewed hashes were refreshed.

Before the fixes, the new regression selection failed 12 cases and passed 12 controls on each framework, reproducing both false-deadlock reports.

Local Release validation:

Check .NET 10 .NET 8
Targeted waits, cancellation ordering, and monitors 111 passed 100 passed
Full rewriting suite, including API discovery and constructor regressions 177 passed 124 passed
IL verification of BugFinding and Rewriting assemblies Passed Passed
Repository IL-diff hash gate 5/5 passed 5/5 passed

The full solution build passed, including the netstandard2.0 targets. Build warnings were limited to NU1900 because NuGet vulnerability metadata was unreachable. The existing .NET 10 inline-array-helper ILVerify exclusion was retained; no new exclusions were added.

These changes are pushed for re-review; this is not a claim of reviewer approval or of a completed upstream CI run.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved scheduling, validation, and test-observation issues can stall valid executions or modify output before rejecting a rewrite.

5 open issues
What changed in this PR

Adds .NET 10 support to Coyote’s build, runtime interception, tooling, and compatibility checks while retaining .NET 8 support.

Changes:

  • Adds .NET 10 targets, dependencies, SDK setup, and package-consumer checks.
  • Extends synchronization rewriting and cancellation handling, with host/target compatibility validation.
  • Adds regression tests and documents runtime compatibility and modeling boundaries.
File Description
Tools/​Coyote/​Coyote.csproj Adds .NET 10 host dependencies.
Tools/​CoverageReportMerger/​CoverageReportMerger.csproj Adds .NET Framework compatibility dependencies.
Tools/​CLI/​Coyote.CLI.csproj Adds .NET 10 CLI dependencies.
Tests/​Tests.Tools/​Tests.Tools.csproj Updates xUnit and warning exclusions.
Tests/​Tests.Runtime/​Tests.Runtime.csproj Updates xUnit and warning exclusions.
Tests/​Tests.Rewriting/​Types/​VolatileRewritingTests.cs Checks native barriers and controlled volatile accesses.
Tests/​Tests.Rewriting/​Types/​TimeoutOverloadRewritingTests.cs Tests interception of timeout overloads.
Tests/​Tests.Rewriting/​Types/​TaskWaitAsyncRewritingTests.cs Tests WaitAsync rewriting and outcomes.
Tests/​Tests.Rewriting/​Types/​TaskRewritingTests.cs Adds modern task API rewriting coverage.
Tests/​Tests.Rewriting/​Types/​LockRewritingTests.cs Tests controlled Lock behavior and compiler lowering.
Tests/​Tests.Rewriting/​Types/​InterlockedRewritingTests.cs Checks small-integer and generic atomic rewriting.
Tests/​Tests.Rewriting/​Tests.Rewriting.csproj Updates xUnit and warning exclusions.
Tests/​Tests.Rewriting/​Methods/​UnsupportedSynchronizationRewritingTests.cs Tests unsupported synchronization diagnostics.
Tests/​Tests.Rewriting/​Methods/​HostRuntimeValidationTests.cs Tests host compatibility checks and rejection safety.
Tests/​Tests.Rewriting/​Methods/​AsyncMethodRewritingTests.cs Adds ValueTask rewriting cases.
Tests/​Tests.Common/​Threading/​NamedEventProvider.cs Provides native named-event observations.
Tests/​Tests.Common/​Threading/​InterlockedProvider.cs Provides native atomic-operation comparisons.
Tests/​Tests.Common/​Tests.Common.csproj Updates shared test dependencies.
Tests/​Tests.Common/​Tasks/​WaitAsyncSourceEvent.cs Defines task completion event cases.
Tests/​Tests.Common/​Tasks/​WaitAsyncProvider.cs Provides native WaitAsync outcome comparisons.
Tests/​Tests.Common/​Tasks/​WaitAllProvider.cs Provides native blocked-wait comparisons.
Tests/​Tests.BugFinding/​Threads/​ThreadRunTests.cs Checks stopped thread state as a flag.
Tests/​Tests.BugFinding/​Tests.BugFinding.csproj Updates xUnit and warning exclusions.
Tests/​Tests.BugFinding/​Tasks/​Join/​TaskWhenEachTests.cs Tests controlled task completion enumeration.
Tests/​Tests.BugFinding/​Tasks/​Join/​TaskWaitTests.cs Adds cancellation and deadlock coverage.
Tests/​Tests.BugFinding/​Tasks/​Join/​TaskWaitAllTests.cs Tests cancellation and completion ordering.
Tests/​Tests.BugFinding/​Synchronization/​VolatileTests.cs Tests volatile scheduling and barrier behavior.
Tests/​Tests.BugFinding/​Synchronization/​MonitorTests.cs Tests nonblocking monitor acquisition.
Tests/​Tests.BugFinding/​Synchronization/​InterlockedTests.cs Tests expanded atomic contracts and scheduling.
Tests/​Tests.BugFinding/​ConcurrencyFuzzing/​Tasks/​TaskWaitAsyncTests.cs Tests WaitAsync under concurrency fuzzing.
Tests/​Tests.Actors/​Tests.Actors.csproj Updates xUnit and warning exclusions.
Tests/​Tests.Actors.BugFinding/​Tests.Actors.BugFinding.csproj Updates xUnit and warning exclusions.
Tests/​get-rewriting-diff-logs.ps1 Makes diff-log collection framework-selectable.
Tests/​Compatibility/​run-package-smoke.ps1 Tests locally packaged libraries and CLI.
Tests/​Compatibility/​run-compatibility-matrix.ps1 Exercises supported and rejected host/target pairings.
Tests/​Compatibility/​README.md Documents compatibility validation procedures.
Tests/​Compatibility/​Net8Probe/​Net8Probe.csproj Defines the .NET 8 consumer probe.
Tests/​Compatibility/​Net8Probe/​global.json Pins the probe’s .NET 8 SDK.
Tests/​Compatibility/​Net8Probe/​CompatibilityProbe.cs Exercises monitor and task control.
Tests/​Compatibility/​Net10Probe/​Net10Probe.csproj Defines the .NET 10 consumer probe.
Tests/​Compatibility/​Net10Probe/​global.json Pins the probe’s .NET 10 SDK.
Tests/​Compatibility/​Net10Probe/​CompatibilityProbe.cs Exercises Lock and modern task calls.
Tests/​compare-rewriting-diff-logs.ps1 Adds framework-specific rewriting baselines.
Source/​Test/​Test.csproj Adds .NET 10 dependency-model support.
Source/​Test/​SystematicTesting/​TestMethodInfo.cs Validates targets before test assembly loading.
Source/​Test/​Runtime/​TargetRuntimeValidator.cs Adds host/target runtime compatibility checks.
Source/​Test/​Rewriting/​Types/​Threading/​Volatile.cs Documents native memory-barrier handling.
Source/​Test/​Rewriting/​Types/​Threading/​Tasks/​WhenEachState.cs Implements controlled completion enumeration.
Source/​Test/​Rewriting/​Types/​Threading/​Monitor.cs Adds nonblocking acquisition and timeout overload support.
Source/​Test/​Rewriting/​Types/​Threading/​Lock.cs Adds controlled Lock and scope replacements.
Source/​Test/​Rewriting/​Types/​Threading/​Interlocked.cs Adds expanded atomic overloads and generic contracts.
Source/​Test/​Rewriting/​Types/​Threading/​EventWaitHandle.cs Adds new constructors and rejects named events.
Source/​Test/​Rewriting/​Types/​NameCache.cs Registers Lock type names.
Source/​Test/​Rewriting/​RewritingOptions.cs Recognizes the .NET 10 target framework.
Source/​Test/​Rewriting/​RewritingEngine.cs Adds explicit-target compatibility preflight.
Source/​Test/​Rewriting/​Passes/​Rewriting/​UncontrolledInvocationRewritingPass.cs Expands unsupported synchronization detection.
Source/​Test/​Rewriting/​Passes/​Rewriting/​Types/​TypeRewritingPass.cs Maps Lock and scope replacements.
Source/​Test/​Rewriting/​AssemblyInfo.cs Validates runtime compatibility of rewrite dependencies.
Source/​Core/​Runtime/​TaskServices.cs Adds cancellation-aware controlled waits.
Source/​Core/​Core.csproj Limits legacy task extensions to older targets.
Scripts/​run-tests.ps1 Adds .NET 10 testing and verification support.
Scripts/​run-benchmarks.ps1 Uses the .NET 10 benchmark runner.
Scripts/​run-benchmark-history.ps1 Selects the .NET 10 benchmark output.
Scripts/​gen-docs.ps1 Generates documentation from .NET 10 binaries.
Scripts/​common.psm1 Updates host signing and runtime selection.
Scripts/​CI/​azure-nuget-sign-publish.yml Adds .NET 10 SDK installation and signing.
Scripts/​build.ps1 Serializes solution builds.
Samples/​Scripts/​build.ps1 Restores the sample-specific tool manifest.
Samples/​Scripts/​build-tests.ps1 Restores the sample-specific tool manifest.
Samples/​.config/​dotnet-tools.json Defines the samples’ local Coyote tool.
PR-524-REVIEW-PLAN.md Records remediation planning and validation criteria.
global.json Selects the .NET 10 SDK.
docs/​concepts/​binary-rewriting.md Documents host selection and synchronization boundaries.
Common/​build.props Adds .NET 10 targeting and language settings.
.github/​workflows/​test-performance.yml Installs the .NET 10 SDK.
.github/​workflows/​test-coyote.yml Adds compatibility and package smoke checks.
.github/​workflows/​codeql-analysis.yml Installs the .NET 10 SDK.
.config/​dotnet-tools.json Updates ILVerify and separates the sample CLI tool.

Review effort: Balanced

Comment on lines +97 to +99
foreach (string assemblyPath in this.Options.AssemblyPaths)
{
TargetRuntimeValidator.ValidateRewritingTarget(assemblyPath);
/// </summary>
public static bool TryEnter(object obj, int millisecondsTimeout)
{
var runtime = CoyoteRuntime.Current;
Comment on lines +552 to +571
if (this.Owner != null && this.Owner != op)
{
return false;
}

// Reference count this access before reaching any scheduling point, else another operation
// can enter and exit this lock in the meantime, which would remove this instance from the
// cache and orphan the lock that this operation is about to acquire.
SystemInterlocked.Increment(ref this.UseCount);
if (runtime.Configuration.IsLockAccessRaceCheckingEnabled && this.Owner is null)
{
// If this operation is trying to acquire this lock while it is free, then inject a scheduling
// point to give another enabled operation the chance to race and acquire this lock.
runtime.ScheduleNextOperation(default, SchedulingPointType.Acquire);
if (this.Owner != null && this.Owner != op)
{
this.ReleaseUse();
return false;
}
}
Comment on lines +167 to +169
await AsyncConditionAwaiterStateMachine.RunAsync(state.Runtime,
() => state.HasCompletedTask() || cancellationToken.IsCancellationRequested,
debugMsg: "any of the enumerated tasks to complete");
<NetStandard2Supported>false</NetStandard2Supported>
<IsPackable>false</IsPackable>
<NoWarn>$(NoWarn),1591</NoWarn>
<NoWarn>$(NoWarn),1591,xUnit1028,xUnit2020,xUnit1030,xUnit1031</NoWarn>

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants