-
Notifications
You must be signed in to change notification settings - Fork 805
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
allow method idx + 1 index #6425
Conversation
// idx 0x10000 is allowed for method table idx + 1 for just beyond last index of method table | ||
if idx > 0x10000 then | ||
System.Diagnostics.Debug.Assert (false, "EmitZUntaggedIndex: too big for small address or simple index") | ||
buf.EmitInt32AsUInt16 idx |
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.
So when an idx of 0x10000 is passed in, 0x0000 is written to buffer by this, which is identical to passing an idx of 0x0000. Is that actually what we want?
Yeah it is weird isn't it. The above is certainly what Mono.Cecil does, at least as far as I can tell. We can check a few other binary writers too, e.g. create a binary with exactly 65535 methods using ILASM. I was hoping to verify by simply executing but we are currently hitting this problem on small variations of FSHarp.Compiler.Service.dll and executing that's a little awkward except in tests. Also testing it that way isn't really good enough is it. [ I'm still searching for where the Another approach would be to refuse to emit a binary with 65535 methods and emit a dummy. I'll create a fake C# binary where one class has 65535 methods and compare. |
Actually I think the problem can only occur when
Sure enough, the last type we're emitting is In the ECMA 335 spec, it says that each
Since there is no next row in the I'm actually beginning to believe this is a flaw in the .NET IL binary format.... Wow.... You simply can't represent this case, can you? [ Update: @jbevian and I have concluded that index 0 is right value to represent the empty list of methods in this case ] |
:) |
@jbevain Have I got this wrong? |
@dsyme no I think you're spot on, I was just amused. Thinking about it this could show up elsewhere as well, I think properties and events also use ranges in a list. |
@jbevain Should |
Yeah, also method parameters. Though maybe the fact that all methods have a |
@dsyme that might work. That reminds me of an issue in Cecil that was triggered by the portable pdb support in |
It looks like Mono.Cecil handles a list start range of zero: So I think 0 is the right value to emit here. But Ecma 335 just doesn't document it |
There is this note in ECMA 335 on a different section. So yes, it looks like 0 is the right thing to emit.
|
That was added in August 2017: So yes, not a common case, but jbevain/cecil@22b36c3#diff-017638b7843cd5d111c30dbc445d39ec Where |
OK, I updated the PR so our binary reader respects '0' in the start-of-list entries to mean an empty list. I think the PR is sound now, but we should really double check the code for the .NET runtime binary reader - I'm sure it will record a zero entry as an empty list to. |
@dsyme, I think you are right that they use 0 as the start row id to indicate 0 methods, fields and properties. GetMethodRange for a type returns the start and end row in the method table: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs#L864 In methoddefinitionhandlecollection here: https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeSystem/HandleCollections.TypeSystem.cs#L456 Notice the count property is last - first + 1, (0 - 1 +1) = 0 |
@dsyme, this looks ready to pull, are you good with it? |
Fixes #6417 , which happens when we write a binary with exactly 65535 methods.
I checked the binary writer code in Mono.Cecil and our computations for sizes are correct, as is our token writing code. The issue happens because an empty type definition (no methods) emits a "method table idx + 1" value, but that is expected.
https://github.com/jbevain/cecil/blob/ab5075b3a885ffd5bee5d347b79ce71aabeb32d1/Mono.Cecil.Metadata/Buffers.cs#L99
I'm testing the compiler referenced in the bug by hand