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

Fix Activator.CreateInstance(GetType(), ...) related ILLink warnings in System.Data.Common #54680

Merged
merged 1 commit into from
Jun 24, 2021

Conversation

krwq
Copy link
Member

@krwq krwq commented Jun 24, 2021

No description provided.

@krwq krwq added the linkable-framework Issues associated with delivering a linker friendly framework label Jun 24, 2021
@ghost
Copy link

ghost commented Jun 24, 2021

Tagging subscribers to 'linkable-framework': @eerhardt, @vitek-karas, @LakshanF, @sbomer, @joperezr
See info in area-owners.md if you want to be subscribed.

Issue Details
Author: krwq
Assignees: -
Labels:

linkable-framework

Milestone: -

@dotnet-issue-labeler
Copy link

Note regarding the new-api-needs-documentation label:

This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change.

@@ -202,7 +203,7 @@ public DataTableMappingCollection TableMappings
[Obsolete("CloneInternals() has been deprecated. Use the DataAdapter(DataAdapter from) constructor. https://go.microsoft.com/fwlink/?linkid=14202")]
protected virtual DataAdapter CloneInternals()
{
DataAdapter clone = (DataAdapter)Activator.CreateInstance(GetType(), System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null)!;
DataAdapter clone = (DataAdapter)Activator.CreateInstance(GetType())!;
Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@eerhardt eerhardt left a comment

Choose a reason for hiding this comment

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

:shipit:

Copy link
Member

@GrabYourPitchforks GrabYourPitchforks left a comment

Choose a reason for hiding this comment

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

The change to Activator.CreateInstance LGTM.

@krwq krwq merged commit 5a238f8 into dotnet:main Jun 24, 2021
@@ -2304,6 +2305,8 @@ public void AcceptChanges()

// Prevent inlining so that reflection calls are not moved to caller that may be in a different assembly that may have a different grant set.
[MethodImpl(MethodImplOptions.NoInlining)]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Copy link
Member

Choose a reason for hiding this comment

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

What is going to keep the parameterless constructor alive if some 3rd party code inherits from DataTable?

I do not think DynamicallyAccessedMembers applies to child types. This UnconditionalSuppressMessage does not look 100% correct to me.

Copy link
Member

Choose a reason for hiding this comment

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

There are 2 different concerns at play here.

What is going to keep the parameterless constructor alive if some 3rd party code inherits from DataTable?

The [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.NonPublicConstructors)] attribute on the DataTable class itself preserves the parameterless ctor for DataTable and all derived types it marks. See dotnet/linker#1929.

This UnconditionalSuppressMessage does not look 100% correct to me.

This suppress message actually suppressing a warning that is 1 step down from the problem at hand. Because this change is adding DynamicallyAccessedMembers(NonPublicConstructors) to the DataTable class itself, and the DataTable class has non-public ctors that are marked with RequiresUnreferencedCode (specifically, the SerializationInfo, StreamingContext ctor), the linker is now issuing a new warning that it looks like we are reflecting against this "unsafe" serialization ctor. That is the warning that is being suppressed here. It is fine to suppress the warning because this code will never find that ctor, since that ctor has parameters and this is looking for a parameterless ctor.

Copy link
Member

Choose a reason for hiding this comment

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

Ah ok. Thank you for the explanation.

Copy link
Member Author

Choose a reason for hiding this comment

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

AFAIK DynamicallyAccessedMembers put on a class flows into derived classes. Suppression is because Activator.CreateInstance(GetType()) doesn't look at the arguments so if any of the ctors has RUC it will show you the warning (here we have SerializationContext ctor with RUC) but we know we can only hit parameterles constructor and SerializationContext ctor will never get executed. cc: @vitek-karas

Copy link
Member

Choose a reason for hiding this comment

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

Both @eerhardt and @krwq are correct. The semantic of putting DynamicallyAccessedMembers on a type are such that it applies to the type and all the derived types (in case of an interface it applies to all implementations of the interface). The behavior is not automatic, the attribute is only applied if trimmer can find a use case for it. The use case currently is a call to variable.GetType() where variable is of static type TBase and TBase has DynamicallyAccessedMembers (or it derives from type which has it).

The second part about the need for suppression is also correct and it's basically a current limitation. The DynamicallyAccessedMemberTypes only has PublicParameterlessConstructor, PublicConstructors and NonPublicConstructors. So it can't express the exact requirements of "public or non-public parameterless constructor". So the current way to do this is to specify PublicParameterlessConstructor | NonPublicConstructors which will mark additional non-public constructors with parameters. In this case one of them has a RUC and so trimmer reports a warning.

There's a discussion about adding some way to specify "public or non-public parameterless constructor" here: dotnet/linker#1688

@ghost ghost locked as resolved and limited conversation to collaborators Jul 25, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Data linkable-framework Issues associated with delivering a linker friendly framework new-api-needs-documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants