Description
Context:
While working with IL bytecode I noticed that e.g. in PresentationCore.dll of WPF there is a method which uses the cpblk instruction original code. The compiled IL code looks as follows:
.method assembly static int16 MS.Internal.TtfDelta.ReadBytes (
valuetype MS.Internal.TtfDelta.TTFACC_FILEBUFFERINFO* pInputBufferInfo,
uint8* puchBuffer,
uint32 modopt([System.Runtime.CompilerServices.VisualC]System.Runtime.CompilerServices.IsLong) ulOffset,
uint32 modopt([System.Runtime.CompilerServices.VisualC]System.Runtime.CompilerServices.IsLong) Count
) cil managed
IL Code Stack (with unsigned types)
[...]
IL_000e: ldarg.1 [byte*]
IL_000f: ldarg.2 [uint, byte*]
IL_0010: conv.u8 [ulong, byte*]
IL_0011: ldarg.0 [TTFACC_FILEBUFFERINFO*, ulong, byte*]
IL_0012: ldind.i8 [long, ulong, byte*]
IL_0013: add [ulong, byte*]
IL_0014: ldarg.3 [uint, ulong, byte*]
IL_0015: conv.u8 [ulong, ulong, byte*]
IL_0016: unaligned. 1
IL_0019: cpblk [EMPTY]
[...]
I know the stack only knows int32, int64, nint, F, O, & . I just have the real types in the diagram for demonstration what the code is effectively doing
According to III.3.30 cpblk requires the inputs of destaddr and srcaddr either to be IntPtr or managed pointer &.
However, supposing my stack diagram is correct, the instruction in this code gets an ulong for srcaddr. I'm a little confused what's going on here or why this is correct. For older PresentationCore.dll I also found situations where uint was used for srcaddr but I suppose this is because of the target architecture being x86 or x64?
Reproduction Steps
I tried to create a simple example app which should work like the example form PresentationCore.
It looks as follows:
.assembly A
{
.ver 0:0:0:0
}
.class public auto ansi abstract sealed beforefieldinit C
extends [mscorlib]System.Object
{
.method private hidebysig static void Main () cil managed
{
.maxstack 8
.entrypoint
.locals init (
[0] valuetype S,
[1] valuetype S
)
IL_0000: ldloca.s 0
IL_0002: ldloca.s 1
IL_0003: ldind.u8
IL_0004: ldc.i8 8
IL_000d: conv.u8
IL_000e: unaligned. 1
IL_000f: cpblk
IL_0011: ret
}
}
.class private sequential ansi sealed beforefieldinit S
extends [mscorlib]System.ValueType
{
}
Expected behavior
Actually, I would expect that the code provided in the description does not even exist, because the spec does not cover the case you can observe in the PresentationCore.dll code.
However on I.8.7.3 ECMA says:
A location type T is assignable-to a location type U if one of the following holds:
[...]
4. T has intermediate type native int and U has intermediate type int32, or vice-versa.
However, I'm not sure whether this rule applies to operation on the stack. I'd expect that even if nint assignable-to int32 IL code requires explicit conversion, since cpblk is not a method call. If it was a method then of course III.1.6 implicit argument coercion would apply.
Furthermore the mentioned rule 4 in I.8.7.3 seems not to be implemented anywhere in CLR and NativeAOT (CastingHelpers.cs) .
E.g.
typeof(int).IsAssignableTo(typeof(nint)); // False
typeof(int).IsAssignableTo(typeof(IntPtr)); // False
typeof(nint).IsAssignableTo(typeof(int)); // False
typeof(nint).IsAssignableTo(typeof(int)); // False
always returns false. As far as I can tell rules from I.8.7.3 are never mentioned, just the ones from I.8.7.1 or I.8.7.2.
Actual behavior
Running the code form the Repro text, results in a NullReferenceException. This is kind of expected and even the spec tells to throw this exceptions in situations where an invalid address was detected.
Yet this still does not explain why such code gets compiled at all, either crafted (as the repro examble) or in binaries like PresentationCore.dll
Regression?
No response
Known Workarounds
No response
Configuration
No response
Other information
As i said, I'm a little confused for the whole situation. It could be possible that I over/misread some parts of the ecma spec, tho currently to me it feels as there is some documentation missing regarding nint and int/long compatibility on opcode input parameters.
Regarding the not covered rule 4 of I.8.7.3 I'd like to know if this really is not implemented in CLR or, if it is, where I can find it.
category:correctness
theme:floating-point
skill-level:intermediate
cost:small
impact:small
Description
Context:
While working with IL bytecode I noticed that e.g. in
PresentationCore.dllof WPF there is a method which uses thecpblkinstruction original code. The compiled IL code looks as follows:I know the stack only knows
int32, int64, nint, F, O, &. I just have the real types in the diagram for demonstration what the code is effectively doingAccording to
III.3.30cpblkrequires the inputs ofdestaddrandsrcaddreither to beIntPtror managed pointer&.However, supposing my stack diagram is correct, the instruction in this code gets an
ulongforsrcaddr. I'm a little confused what's going on here or why this is correct. For older PresentationCore.dll I also found situations whereuintwas used forsrcaddrbut I suppose this is because of the target architecture being x86 or x64?Reproduction Steps
I tried to create a simple example app which should work like the example form PresentationCore.
It looks as follows:
Expected behavior
Actually, I would expect that the code provided in the description does not even exist, because the spec does not cover the case you can observe in the PresentationCore.dll code.
However on
I.8.7.3ECMA says:However, I'm not sure whether this rule applies to operation on the stack. I'd expect that even if
nint assignable-to int32IL code requires explicit conversion, sincecpblkis not a method call. If it was a method then of courseIII.1.6implicit argument coercion would apply.Furthermore the mentioned rule 4 in
I.8.7.3seems not to be implemented anywhere in CLR and NativeAOT (CastingHelpers.cs) .E.g.
always returns false. As far as I can tell rules from
I.8.7.3are never mentioned, just the ones fromI.8.7.1orI.8.7.2.Actual behavior
Running the code form the Repro text, results in a
NullReferenceException. This is kind of expected and even the spec tells to throw this exceptions in situations where an invalid address was detected.Yet this still does not explain why such code gets compiled at all, either crafted (as the repro examble) or in binaries like PresentationCore.dll
Regression?
No response
Known Workarounds
No response
Configuration
No response
Other information
As i said, I'm a little confused for the whole situation. It could be possible that I over/misread some parts of the ecma spec, tho currently to me it feels as there is some documentation missing regarding
nintandint/longcompatibility on opcode input parameters.Regarding the not covered rule 4 of
I.8.7.3I'd like to know if this really is not implemented in CLR or, if it is, where I can find it.category:correctness
theme:floating-point
skill-level:intermediate
cost:small
impact:small