Runtime: InvalidProgramException when accessing struct IReadOnlyList<T> in Expression<T>

Created on 1 Sep 2020  路  8Comments  路  Source: dotnet/runtime

Description

The code included below crashes with the following exception:

Unhandled exception. System.InvalidProgramException: Common Language Runtime detected an invalid program.
   at ConsoleApp1.Program.Main(String[] args)

I expected the code to do nothing at all, since I am not even evaluating the IQueryable.

```c#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp1
{
internal struct ReadOnlyList : IReadOnlyList
{
public int Count
=> throw new Exception();

    public T this[int index]
        => throw new Exception();

    public IEnumerator<T> GetEnumerator()
    {
        throw new Exception();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    IEnumerator<T> IEnumerable<T>.GetEnumerator()
    {
        return GetEnumerator();
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var list = default(ReadOnlyList<string>);
        var unused = Array.Empty<int>()
            .AsQueryable()
            .Select(x => list[x]);
    }
}

}
```

Configuration

.NET SDK (reflecting any global.json):
Version: 5.0.100-preview.8.20417.9
Commit: fc62663a35

Runtime Environment:
OS Name: Windows
OS Version: 10.0.19041
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.100-preview.8.20417.9\

Host (useful for support):
Version: 5.0.0-preview.8.20407.11
Commit: bf456654f9

Regression?

Yes, compared to 3.1.

Other information

  • Replacing the implemented interface IReadOnlyList<T> with IEnumerable<T> resolves the crash.
  • Replacing the type argument of ReadOnlyList<string> with a value type resolves the crash.
  • Turning the struct ReadOnlyList<T> into a class resolves the crash.
  • The code where I originally discovered the issue did not use IQueryable, but a custom method accepting Expression<T>.
area-CodeGen-coreclr blocking-release bug regression-from-last-release

Most helpful comment

Regression introduced by my change #38229 . I will take a look.

All 8 comments

Tagging subscribers to this area: @eiriktsarpalis
See info in area-owners.md if you want to be subscribed.

I have narrowed it down to a generic struct implementing an interface being used in an expression
```C#
public interface IInterface
{
string this[int index] { get; }
string B();
}

public readonly struct GenericStruct : IInterface
{
public string this[int index]
=> throw new Exception();

public string B() => "B";

}

internal class Program
{
private static void Main(string[] args)
{
Debugger.Break();
Expression, string>> funcE = x => x.B();
Func, string> f = funcE.Compile();
}
}
```
when you try to break on even on the first line, the debugger doesn't reach the line
image

thrown from https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/jitinterface.cpp#L3085

// There is a pathological case where invalid IL refereces __Canon type directly, 
but there is no dictionary availabled to store the lookup.

https://github.com/dotnet/runtime/pull/38229 ?

This is a regression from 3.1. Doesn't appear to be specific to collections. CodeGen team, have a look. I reproed on RC1. Could be important for 5.0. cc @jeffschwMSFT @jkotas

@JulieLeeMSFT

@CarolEidt please take a look.

Regression introduced by my change #38229 . I will take a look.

Closing this because it is merged to RC2 now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bencz picture bencz  路  3Comments

Timovzl picture Timovzl  路  3Comments

v0l picture v0l  路  3Comments

matty-hall picture matty-hall  路  3Comments

btecu picture btecu  路  3Comments