Roslyn: [readonly-ref] Copy slice to stackalloc'ed Span may expose referenced variables?

Created on 5 Sep 2017  路  5Comments  路  Source: dotnet/roslyn

Version Used:

2.6.0-rdonly-ref-62101-05

Steps to Reproduce:

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <LangVersion>7.2</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Net.Compilers" Version="2.6.0-rdonly-ref-62101-05" />
    <PackageReference Include="System.Memory" Version="4.5.0-preview2-25701-02" />
  </ItemGroup>

</Project>
static class Program
{
    static void Main()
    {
        Foo(new byte[1000]);
    }

    static void Foo(System.ReadOnlySpan<byte> input)
    {
        System.Span<byte> temp = stackalloc byte[16];

        input.Slice(123, temp.Length).CopyTo(temp);
    }
}

Actual Behavior:

  • Program.cs(12,46,12,50): error CS8526: Cannot use local 'temp' in this context because it may expose referenced variables outside of their declaration scope
  • Program.cs(12,9,12,51): error CS8524: This combination of arguments to 'ReadOnlySpan.CopyTo(Span)' is disallowed because it may expose variables referenced by parameter 'destination' outside of their declaration scope

What's wrong?

cc @VSadov
(Not sure if issues are the best way to ask these kind of questions...)
(Apologies if this is a duplicate or not intended to work yet.)

Area-Compilers

Most helpful comment

Should be fixed in https://github.com/dotnet/roslyn/pull/21881

2.6.0-rdonly-ref-62106-01 should have the fix.

All 5 comments

Noticed that too. Inconvenient indeed.
ReadOnlySpan should be a readonly struct, but not marked as such yet. Compiler thinks that CopyTo may modify its own instance in unsafe manner using the provided stackallocated data.
ROspan and regular spans are immutable and should be 'readonly', then compiler can know it cannot happen.
As a temporary fix we should make compiler just treat them as 'readonly' regardless of being marked or not.

Making Span\

static class Program
{
    static void Main()
    {
        System.Span<byte> foo = new byte[32];

        System.Span<byte> bar = stackalloc byte[16];

        foo = bar;
    }
}
  • Program.cs(9,15,9,18): error CS8526: Cannot use local 'bar' in this context because it may expose referenced variables outside of their declaration scope

The memory referenced by foo and the memory referenced by bar have different lifetimes, but both the variable foo and the variable bar and the memory referenced by bar have the same scope. Assigning bar to foo does not expose the memory referenced by bar outside its scope. This looks perfectly safe to me. Am I missing something?

@ektrah foo can be returned from the containing method if needed, but bar cannot.
It is not the assignment that is a problem, but what it can enable.

Assigning a value with narrower scope/lifetime to a variable with wider can allow scenarios that should not be valid for bar.
The error on such assignment is expected.

I will make compiler to specialcase Span/ReadOnlySpan as 'readonly' regardless of annotations for now to fix this issue.

Also logged a bug https://github.com/dotnet/corefx/issues/23809 to make sure they are eventually annotated as such.

Should be fixed in https://github.com/dotnet/roslyn/pull/21881

2.6.0-rdonly-ref-62106-01 should have the fix.

Was this page helpful?
0 / 5 - 0 ratings