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

[release/6.0] Handle parameterless ctors in structs in STJ's ReflectionEmitMemberAccessor #67901

Merged
merged 4 commits into from
May 4, 2022

Conversation

EgorBo
Copy link
Member

@EgorBo EgorBo commented Apr 12, 2022

Backport of #62989

Customer Impact

Structs with field initializations (C#10 feature) can cause NRE or AVE exceptions(crashes), minimal repro:

JsonSerializer.Deserialize<Foo>("{}");

public struct Foo
{
    public Foo() {}
    public float A = 1;
}

causes AccessViolationException. There are two bug reports by users against 6.0: #62983 and #67781
This PR fixes this behaviour.

Testing

This PR adds tests

Risk

low

cc @eiriktsarpalis @danmoseley

@ghost
Copy link

ghost commented Apr 12, 2022

Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis
See info in area-owners.md if you want to be subscribed.

Issue Details

Backport of #62989

Customer Impact

Structs with field initializations (C#10 feature) can cause NRE or AVE exceptions(crashes), minimal repro:

JsonSerializer.Deserialize<Foo>("{}");

public struct Foo
{
    public float A = 1;
}

causes AccessViolationException. There are two bug reports by users against 6.0: #62983 and #67781
This PR fixes this behaviour.

Testing

This PR adds tests

Risk

low

cc @eiriktsarpalis @danmoseley

Author: EgorBo
Assignees: EgorBo
Labels:

area-System.Text.Json

Milestone: -

@EgorBo EgorBo added the Servicing-consider Issue for next servicing release review label Apr 12, 2022
@EgorBo EgorBo added this to the 6.0.x milestone Apr 12, 2022
Copy link
Member

@eiriktsarpalis eiriktsarpalis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Egor!

@JulieLeeMSFT
Copy link
Member

@EgorBo please check the test failure. Once it is good, we will request to @jeffschwMSFT for servicing consider.

@JulieLeeMSFT JulieLeeMSFT removed this from the 6.0.x milestone Apr 12, 2022
@jaredpar
Copy link
Member

@RikkiGibson, @jcouv as Chuck is OOF


public struct StructWithPropertyInit
{
public long A { get; set; } = 42;
Copy link
Contributor

@RikkiGibson RikkiGibson Apr 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression we went back and made this an error in the same release we introduced field initializers on structs. It's now required to explicitly declare at least one constructor when field initializers are present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, totally forgot about it, but if I add an explicit parameterless constructor the test case will still be valid for the issue

Copy link
Member

@jeffschwMSFT jeffschwMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. @danmoseley would you also like to review?

@danmoseley
Copy link
Member

Seems good to me. Where is the AV, though? Is that worth a separate fix, or does the JIT generally not promise to not AV on bad IL?

@jeffschwMSFT
Copy link
Member

Unverifiable IL can easily cause the runtime and JIT to lead to crashes. No guarantees with bad IL.

@danmoseley
Copy link
Member

is CI broken?

@danmoseley danmoseley closed this Apr 13, 2022
@danmoseley danmoseley reopened this Apr 13, 2022
@carlossanlop carlossanlop added the Servicing-consider Issue for next servicing release review label Apr 13, 2022
@carlossanlop
Copy link
Member

@danmoseley this was missing the servicing-consider label, I added it. Needs Tactics approval.

@JulieLeeMSFT JulieLeeMSFT added this to the 6.0.x milestone Apr 14, 2022
@ericstj
Copy link
Member

ericstj commented Apr 14, 2022

@eerhardt I see we took a similar fix in DependencyInjection in #59625. Should we backport that to 6.0 as well?

@ericstj
Copy link
Member

ericstj commented Apr 14, 2022

For that matter, if I look at all uses of OpCodes.Newobj I see other places that don't seem to handle value types with constructors.
https://source.dot.net/#System.Private.CoreLib/OpCodes.cs,69b6a0a0bb8ecaa2,references

At least this one seems broken too:

if (type.IsValueType)
{
System.Reflection.Emit.LocalBuilder local = ilg.DeclareLocal(type, type.Name + "Value");
ilg.Ldloca(local);
ilg.InitObj(type);
ilg.Ldloc(local);
}
else
{
// Special case XElement
// codegen the same as 'internal XElement : this("default") { }'
ConstructorInfo ctor = GetConstructor()!;
if (!ctor.IsPublic && type.FullName == "System.Xml.Linq.XElement")
{
Type? xName = type.Assembly.GetType("System.Xml.Linq.XName");
if (xName != null)
{
MethodInfo? XName_op_Implicit = xName.GetMethod(
"op_Implicit",
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
new Type[] { typeof(string) }
);
ConstructorInfo? XElement_ctor = type.GetConstructor(
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public,
new Type[] { xName }
);
if (XName_op_Implicit != null && XElement_ctor != null)
{
ilg.Ldstr("default");
ilg.Call(XName_op_Implicit);
ctor = XElement_ctor;
}
}
}
ilg.New(ctor);
}

@leecow leecow removed the Servicing-consider Issue for next servicing release review label Apr 14, 2022
@leecow leecow added the Servicing-approved Approved for servicing release label Apr 14, 2022
@leecow leecow modified the milestones: 6.0.x, 6.0.6 Apr 14, 2022
@eerhardt
Copy link
Member

I see we took a similar fix in DependencyInjection in #59625. Should we backport that to 6.0 as well?

I'm not sure it would meet the bar. It was never supported in DI before, so it isn't a regression. Also I haven't seen real user feedback needing it. You also don't typically gain anything by using ValueTypes in DI since you are always boxing/unboxing. So you might as well just use a class.

So unless there is a need, I don't think it is necessary to backport to 6.0.

Copy link
Member

@carlossanlop carlossanlop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EgorBo @eiriktsarpalis @layomia @dotnet/area-system-text-json this PR is missing the OOB version bumping changes. Example: https://github.com/dotnet/runtime/pull/67104/files

In the S.T.Json.csproj, need to add this line:

<GeneratePackageOnBuild>true</GeneratePackageOnBuild>

And need to bump the ServicingVersion number to the next one:

    <ServicingVersion>INCREASE ME</ServicingVersion>

@ghost ghost added needs-author-action An issue or pull request that requires more info or actions from the author. and removed needs-author-action An issue or pull request that requires more info or actions from the author. labels May 3, 2022
@eiriktsarpalis
Copy link
Member

@carlossanlop done.

@carlossanlop
Copy link
Member

Failures are unrelated: System.IO.Compression.Tests.ZipFile_Unix.UnixCreateSetsPermissionsInExternalAttributes

@carlossanlop carlossanlop merged commit dbd2a6b into dotnet:release/6.0 May 4, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Jun 3, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json Servicing-approved Approved for servicing release
Projects
None yet
Development

Successfully merging this pull request may close these issues.