ICorProfilerInfo::GetILFunctionBody doesn't return the correct size on methods with SEH?
When calling ICorProfilerInfo::GetILFunctionBody on methods with extra sections at the end, the code size that's returned doesn’t seem to be correct. Here are the actual bytes I get back:
0x0B 0x30 0x02 0x00 0x1C 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x72 0x6B 0x00 0x00 0x70 0x73 0x14 0x00 0x00 0x0A 0x7A 0x26 0x00 0x72 0x75 0x00 0x00 0x70 0x28 0x13 0x00 0x00 0x0A 0x00 0xFE 0x1A 0x01 0x10 0x00 0x00 0x00 0x00 0x01 0x00 0x0C 0x0D 0x00 0x0F 0x01 0x00 0x00 0x01 0x1B 0x30 0x03 0x00
The first 12 should be the fat header:
0x0B 0x30 0x02 0x00 0x1C 0x00 0x00 0x00 0x00 0x00 0x00 0x00Looking at byte 5 (0x1C) it seems that the next 16 bytes after the header are the code (0x1C - 0x0C for the fat header size):
NOP (0x00)
NOP (0x00)
LDSTR (0x72:0x7000006B)
NEWOBJ (0x73:0x0A000014)
THROW (0x7A)
POP (0x26)
NOP (0x00)
LDSTR (0x72:0x70000075)
CALL (0x28:0x0A000013)
NOP (0x00)
RETHROW (0xFE1A)Then the SEH should start on the next byte (since the code is already DWORD aligned):
0x01 0x10 0x00 0x00 0x00 0x00 0x01 0x00 0x0C 0x0D 0x00 0x0F 0x01 0x00 0x00 0x01Looking at the second byte (0x10), there are 16 bytes in the SEH section. However, that leaves the last 4 bytes unaccounted for:
0x1B 0x30 0x03 0x00I've search the documentation and can't find anything about data after the SEH sections. Am I missing something? I feel like a mechanic who finishes rebuilding an engine only to find he has a few parts left over. When I call IMethodMalloc::Alloc I'm not including space for these bytes and it seems to be working correctly, but I'm a little scared that it's just a matter of time before this blows up on me.
Answers
Hi! Thanks for the good amount of detail in this post. I did see your comment on my blog, and have already been thinking about it (sorry it's taking me so long to respond). Your post helps me understand your question even better.
First off, you are correct that the SEH section starts DWORD-aligned after the code, which means 0-3 bytes of padding must occur between the code and first extra section. And yes, the profiler is responsibile for ensuring this padded alignment when it uses SetILFunctionBody. Details are in the ECMA spec, Partition II, 25.4.5.
Secondly, there is a bug (!!) in the CLR Profiling API that can cause GetILFunctionBody to return a size that's too large. GetILFunctionBody unfortunately accounts for this DWORD-alignment twice in some cases, so that, instead of the size it returns accounting for the actual 0-3 bytes for padding, the size it returns can sometimes falsely include 0-6 bytes for padding (although the padding is actually 0-3 bytes). Note that the bytes themselves that GetILFunctionBody returns are correct, so any parsing you do based on the contents of the header should work.
Third, in your example, byte #5 in the header (0x1c) describes the the code size only (not the code size + header size). So in your example there are actually 28 bytes of code, not 16.
I think the above should explain what you're seeing, though let me know if not.
All Replies
Hi! Thanks for the good amount of detail in this post. I did see your comment on my blog, and have already been thinking about it (sorry it's taking me so long to respond). Your post helps me understand your question even better.
First off, you are correct that the SEH section starts DWORD-aligned after the code, which means 0-3 bytes of padding must occur between the code and first extra section. And yes, the profiler is responsibile for ensuring this padded alignment when it uses SetILFunctionBody. Details are in the ECMA spec, Partition II, 25.4.5.
Secondly, there is a bug (!!) in the CLR Profiling API that can cause GetILFunctionBody to return a size that's too large. GetILFunctionBody unfortunately accounts for this DWORD-alignment twice in some cases, so that, instead of the size it returns accounting for the actual 0-3 bytes for padding, the size it returns can sometimes falsely include 0-6 bytes for padding (although the padding is actually 0-3 bytes). Note that the bytes themselves that GetILFunctionBody returns are correct, so any parsing you do based on the contents of the header should work.
Third, in your example, byte #5 in the header (0x1c) describes the the code size only (not the code size + header size). So in your example there are actually 28 bytes of code, not 16.
I think the above should explain what you're seeing, though let me know if not.
Thank you for your response. I feel much better now :)
And thanks for the correction on byte #5. Not sure what I was thinking.


