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

System.InvalidProgramException when constructing a record struct with parameter list and calling the default constructor #58328

Closed
V0ldek opened this issue Dec 14, 2021 · 3 comments · Fixed by #58339
Assignees
Milestone

Comments

@V0ldek
Copy link

V0ldek commented Dec 14, 2021

Version Used:
.NET SDK:
Version: 6.0.100
Commit: 9e8b04bbff

Steps to Reproduce:

  1. Create a record struct with a parameter list with at least two parameters:
public record struct S(char First, char Second)
{
}
  1. Add a constructor that takes a parameter of some type (the exact type seems to not matter):
public record struct S(char First, char Second)
{
    public S(object o)
    {
    }
}
  1. This produces CS8862: A constructor declared in a record with parameter list must have 'this' constructor initializer, which is expected. To fix this error, add a call to the default constructor:
public record struct S(char First, char Second)
{
    public S(object o) : this()
    {
    }
}
  1. Attempt to create an instance of the struct:
var s = new S(new object());

Console.WriteLine(s);

Expected Behavior:
The struct is created and printed with First and Second set to default(char).

Actual Behavior:
A System.InvalidProgramException is thrown during execution:

Unhandled exception. System.InvalidProgramException: Common Language Runtime detected an invalid program. 
    at S..ctor(Object o)                                                                                                    
    at Program.<Main>$(String[] args) in D:\<path_ommited>\Program.cs:line 1

Full code:

Occurs both when running compiled to Debug and Release.

var s = new S(new object());

System.Console.WriteLine(s);

public record struct S(char First, char Second)
{
    public S(object o) : this()
    {
    }
}

https://dotnetfiddle.net/85o0Th

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Dec 14, 2021
@V0ldek
Copy link
Author

V0ldek commented Dec 14, 2021

Additional notes:

  1. Calling the synthesised record constructor with two parameters works:
public record struct S(char First, char Second)
{
    public S(object o) : this(default(char), default(char))
    {
    }
}
  1. The issue does not appear when there is one record parameter:
public record struct S(char First)
{
    public S(object o) : this()
    {
    }
}

HOWEVER then the parameter is initalized to garbage -- in my case it's the char '?', but it's clearly not zero-initialized. Changing the type to int produces a seemingly random value, probably a piece of memory that wasn't initialized.

@V0ldek
Copy link
Author

V0ldek commented Dec 14, 2021

Decompiling with sharplab.io shows me the following IL for the S(object) constructor:

.method public hidebysig specialname rtspecialname 
    instance void .ctor (
        object o
    ) cil managed 
{
    // Method begins at RVA 0x20b0
    // Code size 16 (0x10)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldarg.1
    IL_0003: stfld char S::'<First>k__BackingField'
    IL_0008: ldarg.0
    IL_0009: ldarg.2
    IL_000a: stfld char S::'<Second>k__BackingField'
    IL_000f: ret
} // end of method S::.ctor

Looks invalid to me, there's IL_0009: ldarg.2, while the constructor has only two arguments (this and object o).

@cston
Copy link
Member

cston commented Dec 14, 2021

Thanks for reporting this issue @V0ldek.

I believe the compiler should require that explicit constructors in the record struct call either the implicit primary constructor or another explicit constructor.

The constructors above that call this() should be reported as errors since the primary constructor and explicit constructors have parameters in each case.

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

Successfully merging a pull request may close this issue.

3 participants