-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Resolve ILLink warnings in System.Security.Cryptography.X509Certificates #47345
Conversation
[DynamicDependency("#ctor(System.Net.Http.HttpMessageHandler)", "System.Net.Http.HttpClient", "System.Net.Http")] | ||
[DynamicDependency("#ctor", "System.Net.Http.SocketsHttpHandler", "System.Net.Http")] | ||
[DynamicDependency("#ctor", "System.Net.Http.HttpRequestMessage", "System.Net.Http")] | ||
[DynamicDependency("set_PooledConnectionIdleTimeout", "System.Net.Http.SocketsHttpHandler", "System.Net.Http")] | ||
[DynamicDependency("RequestUri", "System.Net.Http.HttpRequestMessage", "System.Net.Http")] | ||
[DynamicDependency("Send", "System.Net.Http.HttpClient", "System.Net.Http")] | ||
[DynamicDependency("Content", "System.Net.Http.HttpResponseMessage", "System.Net.Http")] | ||
[DynamicDependency("ReadAsStream", "System.Net.Http.HttpContent", "System.Net.Http")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these are now identified by the linker because of the helper type annotation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only
[DynamicDependency("#ctor", "System.Net.Http.HttpRequestMessage", "System.Net.Http")]
is now identified by the linker because of the helper type annotation below.
The rest are unnecessary because the linker is able to directly recognize the types and ctors/properties/methods being used in this method. When it can't recognize the Reflection usage, it warns (like it was previously with httpRequestMessageType
).
{ | ||
HttpRequestMessageType = httpRequestMessageType; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unfortunate that the best way to prevent linker warnings is to add more overhead at runtime (and actually increase binary size with this additional class).
Did you consider just suppressing the warning? It was safe previously and just issuing warnings because the linker couldn't figure that out, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suppressing it is kind of hard because one of the warnings comes from inside the lambda method. So placing the suppression attribute would need to suppress more than necessary.
And in general, the recommendation from @vitek-karas and @MichalStrehovsky has been to favor [DAM]
attributes over DynamicDependency
and Suppress
. The reasoning being is that the linker can verify you've done it correctly. Suppressing the warning could lead to bugs in the future if the code is changed and new warnings get suppressed.
Another approach I thought of, but didn't try was to store HttpRequestMessageType
on a static field with the [DAM]
annotation. I shied away from it because of nullability hoops I'd have to jump through. That would only add an extra reference/pointer statically, instead of a whole new type and object instance here. Thoughts on that approach?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another approach would be to do the closure manually - that would let you add the necessary annotation to the field. The compiler here generates a type and so on for the closure for the returned lambda. That could be done manually... It would avoid the second new type (only the closure type would remain). But it would make the code less readable/maintainable.
You could also simplify the helper type - make it a struct and make the type a field - to reduce the metadata size impact.
I can't see how linker could figure this out without cross-method analysis unfortunately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would grab a ConstructorInfo
for the default constructor in the main method body and just Invoke
it in the lambda. No DynamicallyAccessed
annotations necessary and no extra closures. Illink should be able to figure everything out.
ConstructorInfo
is a good replacement for Activator unless the type in question is a valuetype with no explicit default ctor (in which case we can't get a ConstructorInfo
, but the type can still be CreateInstance
'd).
I wish C# had a way to annotate the closure though :(.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed it to use ConstructorInfo
instead.
This has the drawback of not being able to take advantage of the perf improvements we've made recently in Activator.CreateInstance
(#32520). But we are hitting an HTTP endpoint, so the perf here won't really be noticeable. Also, when we add Activator.CreateFactory
(#36194), we can update this code to use the new API.
{ | ||
HttpRequestMessageType = httpRequestMessageType; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another approach would be to do the closure manually - that would let you add the necessary annotation to the field. The compiler here generates a type and so on for the closure for the returned lambda. That could be done manually... It would avoid the second new type (only the closure type would remain). But it would make the code less readable/maintainable.
You could also simplify the helper type - make it a struct and make the type a field - to reduce the metadata size impact.
I can't see how linker could figure this out without cross-method analysis unfortunately.
Use ConstructorInfo to create HttpRequestMessage instances.
Test failures are #47374. |
Contributes to #45623