-
-
Notifications
You must be signed in to change notification settings - Fork 754
Box value types if passed to ctor args as type object #1020
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
Conversation
…Type This was previously checking whether the declaring type of the member was a value type, not the member itself. This property doesn't seem to be used anywhere and so fixing it shouldn't break anything else (it doesn't impact the unit test results at all).
…to ctor args as type object If the value of a property of type int is used to populate a constructor argument of type object in deserialization then this is allowed by the constructor-matching code because it simply uses IsAssignableFrom as a check for compatability (and object IsAssignable from int) but when the IL is generated to pass an int value as an object, it has to be boxed in order for the code to be valid. See notes at MessagePack-CSharp#987 (comment) that demonstrate how to use the reproduce case to generate a dll that PEVerify can be run against to show that it was invalid before this change. I've added unit tests in this changeset for the fix but I suspect that the test runner would have difficulties executing the tests WITHOUT the fix as the ExecutionEngineError could tear down the process before the test runner could record it as a failure. However, if you were to use Debug Test on one of the tests that I've added but comment out the fix that I put into the DynamicObjectResolver then you would be able to see the ExecutionEngineError be caught by the debugger.
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.
The fix looks well written, but I wonder whether supporting the scenario that requires boxing is the right direction to go here. Why not throw a meaningful exception indicating that the code author should fix their constructor parameter type to match the member type? That would avoid the boxing which avoids unnecessary GC pressure.
@neuecc thoughts?
|
Exception is good. |
|
Upcasting is OK, although that would be weird that the constructor would have to downcast its argument to match the member type. |
|
The serializer doesn't get involved with the body of the constructor. binary -> deserialize field(int) -> constructor(object) It causes only upcast, int -> object. It's more like JSON.NET. MessagePack has a higher chance of successful deserialization than JSON.NET because it is more strictly type-preserving than JSON, so int is int. |
|
Ok, so it sounds like you're in favor of this change. Very well. :) |
|
@ProductiveRage Can you add a test for a ctor parameter type of |
|
@AArnott Sorry it's taken me a few days. I expected that it would work with the scenario that you proposed because I presumed that int would be assignable-from long but that is not the case and the following class: .. will fail at the line The error (as expected) is:
The same error occurs if the constructor argument is a long and the member and int because long is not assignable from int, nor is int assignable from long (they may be cast from one to another but IsAssignableFrom returns false for both directions). Do you think that it makes sense to add any more code for scenarios similar to this in order for my original change to make sense? |
|
Thanks for testing. That exception is good. I don't mind unequal value types failing, but I was hoping it was not a CLR engine exception and your report is that it is not. So that's good. :) |
Hopefully I've included enough information in issue #987 and in the comment for the second changeset in this PR to explain the issue (when an
intmember is serialized and then used to populate anobjectconstructor argument in the deserialization process, this is seen as value as the typeobjectis assignable from the typeintbut the value itself needs to be boxed otherwise the generated IL is invalid, hence the terrifying-sounding ExecutionEngineException).Fixes #987