Skip to content

Bad cast morphing #8749

@mikedn

Description

@mikedn

While working on dotnet/coreclr#12676 I ran into what appears to be a bug in cast morphing. Consider the following IL code:

.assembly extern System.Console {auto}
.assembly extern mscorlib {auto}
.assembly test {}

.class Program
{
	.field static int8 foo;

	.method static int32 Test() 
	{
		.entrypoint
		.maxstack 1
		ldc.i4 -1
		stsfld int8 Program::foo
		ldsfld int8 Program::foo
		conv.ovf.i2.un
		ret
	}
}

This should throw an overflow exception. When foo is loaded the value is sign extended so on the evaluation stack we have -1. But we have conv.ovf.i2.un so the value on the stack is supposed to be treated as 4294967295 and that's too large for i2.

Morph is incorrectly removing the overflow flag from the cast and the following code is generated:

       C605AB49EFFFFF       mov      byte  ptr [reloc classVar[0xb1466240]], -1
       480FBE05A349EFFF     movsx    rax, byte  ptr [reloc classVar[0xb1466240]]
       480FBFC0             movsx    rax, ax

The problem is likely in this fgMorphCast code:

            if (srcSize < dstSize) // widening cast
            {
                // Keep any long casts
                if (dstSize == sizeof(int))
                {
                    // Only keep signed to unsigned widening cast with overflow check
                    if (!tree->gtOverflow() || !unsignedDst || unsignedSrc)
                    {
                        goto REMOVE_CAST;
                    }
                }

                // Casts from signed->unsigned can never overflow while widening

                if (unsignedSrc || !unsignedDst)
                {
                    tree->gtFlags &= ~GTF_OVERFLOW;
                }
            }

In this example srcSize is 1 and dstSize is 2 so it concludes that we have a widening cast to signed and drops the overflow flag. srcSize should really be 4, it's 1 only if the cast doesn't "reinterpret" the sign of the source field.

Also note that the "Casts from signed->unsigned can never overflow while widening" comment is wrong. It should be something like "Casts from unsigned or to signed can never overflow while widening".

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIbug

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions