-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Fix SafeContext of Span-valued collection expressions to match specification #80684
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix SafeContext of Span-valued collection expressions to match specification #80684
Conversation
…ication Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
|
@copilot Please add a new file with path # Breaking changes in Roslyn after .NET 10.0.100 through .NET 11.0.100
This document lists known breaking changes in Roslyn after .NET 10 general release (.NET SDK version 10.0.100) through .NET 11 general release (.NET SDK version 11.0.100).
## The *safe-context* of a collection expression of Span/ReadOnlySpan type is now *declaration-block*
The C# compiler made a breaking change in order to properly adhere to the [ref safety rules](https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#ref-safety) in the *collection expressions* feature specification. Specifically, the following clause:
> * If the target type is a *span type* `System.Span<T>` or `System.ReadOnlySpan<T>`, the safe-context of the collection expression is the *declaration-block*.
Previously, the compiler used safe-context *function-member* in this situation. We have now made a change to use *declaration-block* per the specification. This can cause new errors to appear in existing code, such as in the scenario below:
```cs
scoped Span<int> items1 = default;
scoped Span<int> items2 = default;
foreach (var x in new[] { 1, 2 })
{
Span<int> items = [x];
if (x == 1)
items1 = items; // previously allowed, now an error
if (x == 2)
items2 = items; // previously allowed, now an error
}
```
See also https://github.com/dotnet/csharplang/issues/9750.
|
Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot Looks good, but please address comment #80684 (comment).
|
The error we are fixing here is not a use after free error. It's not a memory safety issue. It is a correctness issue in which the contents of spans are aliased unexpectedly. |
|
Co-authored-by: 333fred <2371880+333fred@users.noreply.github.com>
... Added the breaking changes documentation file in commit 4d0ccc5.
Done. Added the breaking changes documentation in commit 4d0ccc5. |
|
|
||
| ## The *safe-context* of a collection expression of Span/ReadOnlySpan type is now *declaration-block* | ||
|
|
||
| ***Introduced in Visual Studio 2026 version 18.3*** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This version is not out yet, but, assuming we do not backport to 10.0.100, this is when we expect the fix to reach users.
|
Now working on building runtime with the change. |
|
@copilot Please add tests for the following scenarios, nearby to the other tests whose baselines were changed. using System;
class C
{
public C(scoped ReadOnlySpan<int> items)
{
int x = 0;
items = new ReadOnlySpan<int>(ref x); // error
}
void M(scoped ReadOnlySpan<int> items)
{
int x = 0;
items = new ReadOnlySpan<int>(ref x); // ok
}
}using System;
class C
{
public C(scoped ReadOnlySpan<int> items)
{
items = [0]; // error
}
void M(scoped ReadOnlySpan<int> items)
{
items = [0]; // ok
}
}The expectation is actually that both the constructor and ordinary method cases would permit this. Don't attempt to change the implementation to achieve the expected behavior yet. Just create the test methods, passing the source code for the scenarios into CreateCompilation, VerifyDiagnostics etc and paste in the resulting baselines in order to make the tests pass. |
Co-authored-by: RikkiGibson <5833655+RikkiGibson@users.noreply.github.com>
... Added the requested tests in commit 7e2f62f:
The baselines show that:
|
|
@copilot Add a test to CollectionExpressionTests.cs which is similar to This test might fail a debug assertion when it is run, which indicates there is real need for the Please resolve the issue by restoring the override from the original code, and adding a parameter Pass |
…ns (#120771) [Doc for upcoming breaking change](https://github.com/dotnet/roslyn/blob/copilot/fix-safecontext-of-span-collection/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2011.md#the-safe-context-of-a-collection-expression-of-spanreadonlyspan-type-is-now-declaration-block) See dotnet/roslyn#80684. TensorShape's constructor was the only break I found when compiling the libraries. I fixed this by extracting the collection-expression to the top level.
|
@dotnet/roslyn-compiler for review. |
|
@RikkiGibson Are you going to sign-off on this PR? |
|
@333fred Please review as one of the reviewers for "Collection Expressions" feature. |
|
In case @333fred's sign-off is marked "gray", I believe it should count as a full review anyway, because all he did was ask copilot to address my comment. As this is a breaking change I would like to get it in sooner rather than later. Please do take a look when you are available. |
AlekseyTs
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (commit 12)
* upstream/main: (123 commits) Fix SafeContext of Span-valued collection expressions to match specification (dotnet#80684) Improve detection of invalid references for implicitly typed expression variables declared within implicit object creation expressions. (dotnet#80546) Add test demonstrating behavior of ToMinimalDisplayString. (dotnet#80757) Only set DOTNET_HOST_PATH if something was installed (dotnet#80842) Clean up a Razor external access service (dotnet#80830) Remove unused statement (dotnet#80823) Allow foreach on typed null enumerables (dotnet#80783) Update documentation for DeclaringSyntaxReferences and Locations to clarify partial members behavior (dotnet#80704) Fix issue converting an auto prop to a full prop when 'field' and 'initializers' are involved Rename childIsSimple to innerExpressionHasPrimaryPrecedence and add more test cases Remove placeholder WorkItem attributes from new tests Fix RemoveUnnecessaryParentheses to detect simple expressions in bitwise operations [main] Update dependencies from dotnet/arcade (dotnet#80828) Fix ITypeSymbol.BaseType documentation for type parameters (dotnet#80770) soft-select select camelcase matched item if user might be typing an undefined type parameter (dotnet#80809) Allow semantic tokens in Razor to be better behaved (dotnet#80815) Rebase Remove using Update test Add fix all test ...
Fixes #80107
Fixes dotnet/csharplang#9750
Problem
Collection expressions with Span type were incorrectly using
SafeContext.CurrentMethodfor escape analysis, which allowed them to escape their declaring scope. This caused the following problematic code to compile without errors:The issue is that
itemsis a collection expression created in the foreach loop body (a nested scope), but was being allowed to escape to the outer scope and be assigned toitems1anditems2. This is a correctness issue where the contents of spans are aliased unexpectedly.Additionally, there was a related issue where locals in the top-level block of constructors had an incorrect ref-safe-context, causing collection expressions and other constructs to incorrectly produce errors when assigned to scoped parameters in constructors.
Solution
Changed two locations in
Binder.ValueChecks.cs:Line 4588 in
GetValEscape: ChangedSafeContext.CurrentMethodtolocalScopeDepthLine 5336 in
CheckValEscape: ChangedSafeContext.CurrentMethodtoescapeFromFixed ref-safe-context of locals in the top-level block of constructors in
RefSafetyAnalysis.cs:Breaking Change
This is an intentional breaking change to fix incorrect code patterns. After this change, the problematic code above now correctly produces compilation errors:
Documentation
docs/compilers/CSharp/Compiler Breaking Changes - DotNet 11.mddescribing the change and providing workaroundsTest Updates
SpanAssignment_NestedScope_IssueExamplethat validates the fix with the exact scenario from the issueSpanAssignment_ScopedParameter_Constructor_SpanandSpanAssignment_ScopedParameter_Constructor_CollectionExpressionto validate that scoped parameters in constructors work correctly (previously failed, now pass)Fixes #80683
Original prompt
Fixes #80683
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.