Skip to content

JIT: (bug) LEA address-mode folding silently deletes a nested checked multiply (missing OverflowException) #133782

Description

@EgorBo

CodeGen::genCreateAddrMode checks gtOverflow() on the outermost GT_MUL it folds, but the inner scale-folding loops use only GenTree::GetScaledIndex(), which ignores GTF_OVERFLOW. Lowering::TryCreateAddrMode therefore folds b + checked(i * 2) * 4 into LEA(b + i*8) and deletes the MUL_ovfl node, so the mandated OverflowException is never thrown.

Minimal Repro

using System;
using System.Runtime.CompilerServices;

class Program
{
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    static long Test(long b, long i) => b + checked(i * 2) * 4;

    static void Main()
    {
        try { Console.WriteLine(Test(100, 0x4000000000000000)); }
        catch (OverflowException) { Console.WriteLine("OverflowException"); }
    }
}

No JIT env vars required.

Expected

OverflowException

(0x4000000000000000 * 2 overflows Int64, so the mul.ovf must throw.)

Actual

100
; Program:Test(long,long):long (FullOpts)
       lea      rax, [rcx+8*rdx]
       ret
; Total bytes of code 5

The imul/jo/CORINFO_HELP_OVERFLOW sequence is gone. DOTNET_JitDump=Test shows lowering deleting the checked multiply:

Removing unused node:
  N004 (  9,  8) [000004] ---X-+-----     *  MUL_ovfl  long   $141      <<<< checked multiply deleted
New addressing mode node:
  N007 ( 13, 12) [000008] -----+-----     *  LEA(b+(i*8)+0) long

Notes

  • src/coreclr/jit/codegencommon.cpp ~L1596 (op1) and ~L1672 (op2): while ((rv2->OperIs(GT_MUL) || rv2->OperIs(GT_LSH)) && (argScale = rv2->GetScaledIndex()) != 0) swallows rv2 even when rv2->gtOverflow(). A fix is && !rv2->gtOverflow() in both loops, or making GetScaledIndex() return 0 for overflow-checking GT_MUL.
  • Also repros with reversed operand order, with int/ulong, and for other scale pairs (e.g. checked(i * 4) * 2) — any nested pair whose product is a legal x64 LEA scale.
  • The int variant repros even with DOTNET_JITMinOpts=1, since Lowering::LowerAdd calls TryCreateAddrMode unconditionally on xarch.
  • main @ b44cd904110a27d96ea83621e94332d55150d482, windows-x64 Checked corerun; also repros on released .NET 10.0.12, so long-standing rather than a .NET 11 regression.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions