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

BUG: TypeLoadException generated using 3.2.0-beta1-19227-04 #35324

Closed
Korporal opened this issue Apr 28, 2019 · 8 comments
Closed

BUG: TypeLoadException generated using 3.2.0-beta1-19227-04 #35324

Korporal opened this issue Apr 28, 2019 · 8 comments
Assignees
Milestone

Comments

@Korporal
Copy link

Korporal commented Apr 28, 2019

3.2.0-beta1-19227-04:

Create console app that references the type: Item

This was found using VS 2019 (16.0.2) in which I added the beta compiler nuget packages to my solution/projects and set C# build to 8.0 (beta).

I've created a simple way to repro this, the actual code that led to this crash is more involved (e.g. the actual code dynamically computes the T* pointer here it just returns null) but the sample struct seems to accurately recreate the problem, in my case the type Item is in a separate class library assembly (also .Net Standard 2.0) no idea if this is a factor though as I haven't tried it.

  1. See the simple struct attached.
  2. Use .Net Standard 2.0
  3. Create console app that simply refers to the type, eg: Item x = new Item();
  4. Execute the app.

An instance of the type should be created without problems:

TypeLoadException:

Here's the struct - it compiles fine with this beta build and earlier ones, I have tested the runtime fault and it's present in this version and also in 3.1.0-beta3-19213-02 if I recall.

    public struct Item
    {
        internal ItemHolder<Item> next;
        internal ItemHolder<Item> prev;
    }

    public struct ItemHolder<T> where T : unmanaged
    {
        public unsafe T* Data
        {
            get { return null; } // just to get a compile.
        }
    }

If we change this to something like this, we do not get the runtime fault:

    public struct Item
    {
        internal ItemHolder<OtherItem> next;
        internal ItemHolder<OtherItem> prev;
    }

    public struct ItemHolder<T> where T : unmanaged
    {
        public unsafe T* Data
        {
            get { return null; } // just to get a compile
        }
    }

by the way returning a ref rather than a pointer leads to the same exception:

    public struct Item
    {
        internal ItemHolder<Item> next;
        internal ItemHolder<Item> prev;
    }

    public struct ItemHolder<T> where T : unmanaged
    {
        public unsafe ref T Data
        {
            get { return ref Unsafe.AsRef<T>(null); } // just to get a compile.
        }
    }
@Korporal Korporal changed the title TypeLoadException generated using 3.2.0-beta1-19227-04 BUG: TypeLoadException generated using 3.2.0-beta1-19227-04 Apr 29, 2019
@Korporal
Copy link
Author

This may be of interest to @tannergooding and @RikkiGibson since it seems related to issue #31439 which was a recent bug fix.

@Korporal
Copy link
Author

This is present also in latest: 3.2.0-beta1-19229-02

@RikkiGibson
Copy link
Contributor

RikkiGibson commented Apr 30, 2019

Will have a look. Is there any additional error info contained in the exception?

edit: I can repro this in the IDE and see the message:

System.TypeLoadException
  HResult=0x80131522
  Message=Could not load type 'Item' from assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
  Source=<Cannot evaluate the exception source>
  StackTrace:
<Cannot evaluate the exception stack trace>

This seems to happen whether or not the Item declaration is in a netcoreapp3.0 project, net472 project, or a netstandard2.0 project.

@RikkiGibson
Copy link
Contributor

Actually I find that even the following program gets TypeLoadException:

using System;
namespace ConsoleApp9
{
    public struct Item
    {
        internal ItemHolder<Item> next;
        internal ItemHolder<Item> prev;
    }

    public struct ItemHolder<T> { }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(new Item());
        }
    }
}

But this one does not:

using System;
namespace ConsoleApp9
{
    public class Item
    {
        internal ItemHolder<Item> next;
        internal ItemHolder<Item> prev;
    }

    public class ItemHolder<T> { }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(new Item());
        }
    }
}

@RikkiGibson
Copy link
Contributor

It appears this is a known issue noted in dotnet/coreclr#20220

@Korporal
Copy link
Author

Korporal commented May 1, 2019

@RikkiGibson - I got the impression when looking at this that the compiler may be assuming that structs which refer in any way to themselves are invalid because structs are laid out as values not references to values and this clearly leads to infinite recursion.

Of course exposing only a ref T and T* (which were introduced relatively recently) are quite different but the above assumption (if present) might be deeply ingrained in some way.

@RikkiGibson
Copy link
Contributor

This appears to be a runtime issue, and not related to use of T* or ref T. All that's required is for a field within struct Item to have a type argument of type Item, regardless of whether the substitution introduces new fields of type Item into the layout.

@gafter
Copy link
Member

gafter commented Jun 3, 2019

Closing as this is dotnet/coreclr#20220 and https://github.com/dotnet/coreclr/issues/7957

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants