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

CS8353 when trying to initialize Span<T> variable using stackalloc outside of its declaration #25118

Closed
airbreather opened this issue Feb 28, 2018 · 4 comments
Assignees
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design
Milestone

Comments

@airbreather
Copy link

airbreather commented Feb 28, 2018

Version Used:
Visual Studio Community 2017 Preview
15.6.0 Preview 6.0

Steps to Reproduce:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        System.Span<byte> bytes;
        bytes = stackalloc byte[1024];
    }
}

App.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.1</TargetFramework>
    <LangVersion>latest</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Memory" Version="4.5.0-preview1-26216-02" />
  </ItemGroup>

</Project>

Expected Behavior:
This feels like it should be considered safe. The Span<T> never escapes this method.

Actual Behavior:
CS8353: A result of a stackalloc expression of type 'Span<byte>' cannot be used in this context because it may be exposed outside of the containing method.

Workaround:
Joining the declaration and assignment will make the error go away, but that doesn't look amazing in this situation (and this situation doesn't really seem all that esoteric)

Edit: a better workaround for a more "full" version of this repro, from the comments below:

using System;

class Program
{
    static void Main(string[] args)
    {
        int len = ComputeLength();

        Span<byte> bytes = stackalloc byte[0];
        if (len <= 1024)
        {
            bytes = stackalloc byte[len];
        }
        else
        {
            bytes = new byte[len];
        }

        // do stuff with bytes
    }

    static int ComputeLength() => 2048;
}

My Own Guesses:
I'm guessing the analyzer is a bit paranoid here, because it's a lot easier to reject cases like this than to prove that there are no possible ways for this Span<T> to escape whenever it's stack-allocated.

@svick
Copy link
Contributor

svick commented Feb 28, 2018

This would also be useful if TryForSufficientStack is implemented (https:/dotnet/corefx/issues/26954), so that you could write code like the following (from https:/dotnet/corefx/issues/26954#issuecomment-364211315):

Span<SomeStruct> span;
if (RuntimeHelpers.TryEnsureSufficientExecutionStack(list.Count * PUT_HERE_YOUR_STRUCT_SIZE))
{
    span = stackalloc SomeStruct[size];
}
else
{
    span = ArrayPool<SomeStruct>.Shared.Rent(size);
}

@jcouv
Copy link
Member

jcouv commented Feb 28, 2018

Tagging @VSadov @gafter for comment/triage.

@jcouv jcouv added this to the 15.7 milestone Mar 12, 2018
@VSadov
Copy link
Member

VSadov commented Mar 27, 2018

Uninitialized span local is classified as ordinary "returnable" span. Then you cannot assign stackallocated spans to it.

If you initialize with stackalloc SomeStruct[0] , your code will work. As long as you do not try returning the span.

airbreather added a commit to airbreather/NetTopologySuite.Optimized that referenced this issue Mar 28, 2018
@VSadov
Copy link
Member

VSadov commented Apr 2, 2018

The usability issues that come from this behavior are discussed in dotnet/csharplang#1130

For the time being this is ByDesign.

We may need to introduce a feature to make such declarations easier to do.
It looks like stackalloc[0] worked for this case though.

@VSadov VSadov added the Resolution-By Design The behavior reported in the issue matches the current design label Apr 2, 2018
@VSadov VSadov closed this as completed Apr 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers Resolution-By Design The behavior reported in the issue matches the current design
Projects
None yet
Development

No branches or pull requests

4 participants