Skip to content

JIT: (bug) Loop hoisting moves a throwing division above a bounds check, so the wrong exception is raised #133585

Description

@EgorBo

Repro

using System;
using System.Runtime.CompilerServices;

internal static class Program
{
    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
    private static int Test(int[] arr, int idx, int a, int b, int n)
    {
        int r = 0;
        for (int i = 0; i < n; i++)
        {
            r += arr[idx];
            r += a / b;
        }
        return r;
    }

    private static void Main()
    {
        try
        {
            Console.WriteLine(Test(new int[1], 5, 1, 0, 5));
        }
        catch (Exception e)
        {
            Console.WriteLine(e.GetType().Name);
        }
    }
}

arr has length 1 and idx is 5, so the very first statement of the first iteration must fault
before a / b is ever evaluated.

Expected

IndexOutOfRangeException

Actual

DivideByZeroException

Also reproduces on the Release runner with no environment variables set at all.
DOTNET_JitDoLoopHoisting=0 and DOTNET_JITMinOpts=1 both print the correct
IndexOutOfRangeException.

The invariant arr[idx] bounds check is not hoistable, but because it is loop-invariant it does
not close loop hoisting's exception-ordering barrier, so the invariant a / b is hoisted into the
preheader and executes ahead of it.

Platform

Windows x64, .NET 11 (dotnet/runtime main @ a0b86b1, Checked and Release builds). No special
env vars or CPU features required.

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