Skip to content
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

Spread element on initialized inline array throws AccessViolationException #107018

Closed
monkey0506 opened this issue Aug 27, 2024 · 3 comments
Closed

Comments

@monkey0506
Copy link

Description

When creating an inline array via a constructor that assigns the elements of the array, accessing said inline array via a spread element throws a System.AccessViolationException.

Reproduction Steps

For an inline array defined as:

[InlineArray(8)]
public struct InlineIntArray8
{
    private int element0;

    public InlineIntArray8()
    {
        for (int i = 0; i < 8; ++i)
        {
            this[i] = i;
        }
    }
}

Then accessing the inline array such as:

InlineIntArray8 inlineArray = new();
ReadOnlySpan<int> readOnlySpan = [ 5, ..inlineArray ]; // AccessViolationException

Note that the AccessViolationException occurs only when using the spread element on the inline array which has at least one element assigned (this[i] = ...) in the constructor. This does not occur if the array elements are unassigned, nor when performing an implicit/explicit cast from the inline array to ReadOnlySpan<T>/Span<T>.

Expected behavior

The spread element should not throw an exception in this use-case.

Actual behavior

An exception of System.AccessViolationException is thrown when the inline array is accessed via the spread element (in a collection expression). Other uses of the inline array do not throw this exception.

Regression?

Unknown.

Known Workarounds

The inline array can be implicitly/explicitly cast to a span first, and then used by the spread element normally.

ReadOnlySpan<int> intermediateSpan = inlineArray;
ReadOnlySpan<int> targetSpan = [ 5, ..intermediateSpan ];
ReadOnlySpan<int> targetSpan2 = [ 5, ..((ReadOnlySpan<int>)inlineArray) ];

targetSpan and targetSpan2 do not throw an exception.

Configuration

.NET 8
Visual Studio Community 2022 (64-bit) Version 17.8.1
Windows 11

VS version and OS do not seem to affect this issue.

Other information

Via StackOverflow, user Ivan Petrov reports that the spread element is compiled into the following:

Span<int>.Enumerator enumerator = ((Span<int>*)(&inlineArray))->GetEnumerator();

That is, rather than constructing a new span from the inline array, an unsafe cast is performed, incorrectly mapping the inline array onto the memory layout of a Span<T>:

internal readonly ref T _reference;
private readonly int _length;

Because the inline array does not match this layout in memory, the AccessViolationException is thrown.

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Aug 27, 2024
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-memory
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member

Duplicate of dotnet/roslyn#70708

@monkey0506
Copy link
Author

Duplicate of dotnet/roslyn#70708

Ah! Thanks for identifying the existing issue. It's somewhat of a difficult subject to search for, but hopefully the referenced StackOverflow question and workaround is useful to anyone else coming across this.

@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Aug 27, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Sep 28, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants