Browse Source

Decode float/double stackalloc initializer constants by their type

A constant-size stackalloc initializer stores its constant elements through a
data blob (cpblk from a <PrivateImplementationDetails> field). ReadElement
decoded every element by width, so a 4-byte float was read as Int32 and an
8-byte double as Int64. The resulting constant carried the raw bit pattern
(1f decoded as 1.0653532E+09f) and its stack type no longer matched the store,
tripping StObj.CheckInvariant. Dispatch on the element's type code so Single and
Double are read as floating-point, matching the heap-array decoder.

Found while exploring stackalloc-initializer coverage around the element-type
hint fix; floating-point element types had no test case.

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3813/head
Siegfried Pammer 2 weeks ago committed by Siegfried Pammer
parent
commit
a06c22b88a
  1. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs
  2. 10
      ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs

@ -212,6 +212,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -212,6 +212,23 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return UsePointer((byte*)ptr);
}
// Mixed constant/non-constant floating-point initializers go through the constant data
// blob; reading a 'float'/'double' element as the integer of the same width produced the
// raw bit pattern as the literal (e.g. 1f decoded as 1.0653532E+09f).
public unsafe string SimpleStackAllocSingle(float a)
{
float* ptr = stackalloc float[4] { 1f, 2f, 3f, a };
Console.WriteLine(*ptr);
return UsePointer((byte*)ptr);
}
public unsafe string SimpleStackAllocDouble(double a)
{
double* ptr = stackalloc double[4] { 1.0, 2.0, 3.0, a };
Console.WriteLine(*ptr);
return UsePointer((byte*)ptr);
}
public unsafe string SimpleStackAllocInt32NonConstant(int a, int b, int c)
{
int* ptr = stackalloc int[6] { 0, 1, 0, a, b, c };

10
ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

@ -325,6 +325,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -325,6 +325,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
private ILInstruction ReadElement(ref BlobReader blob, IType elementType)
{
// Floating-point elements must be read as their actual type: their stored bytes are
// not the integer of the same width, and the resulting constant has to match the
// element type's stack type (see StObj.CheckInvariant).
switch (ReflectionHelper.GetTypeCode(elementType))
{
case TypeCode.Single:
return new LdcF4(blob.ReadSingle());
case TypeCode.Double:
return new LdcF8(blob.ReadDouble());
}
switch (elementType.GetSize())
{
case 1:

Loading…
Cancel
Save