Skip to content

JIT: assertion 'FitsIn<int32_t>(value)' on constant-folded BitOperations.RotateRight(0xFFFFFFFFu, k) with multiple uses #129099

@AndyAyersMS

Description

@AndyAyersMS

Note

This issue was authored by GitHub Copilot CLI on @AndyAyersMS's machine,
based on a bug surfaced by an experimental in-development fuzzer.
The C# repro is verified.

Repro

using System;
using System.Numerics;
using System.Runtime.CompilerServices;

public static class Program
{
    private static uint Sink;

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static uint Fn()
    {
        uint v2 = BitOperations.RotateRight(0xFFFFFFFFu, 1);
        Sink = v2;
        return v2;
    }

    public static int Main()
    {
        Console.WriteLine($"{Fn():X8}");
        return 0;
    }
}

Observed

Configuration Result
Local dotnet/runtime HEAD Checked, DOTNET_TieredCompilation=0 (FullOpts) JIT assertion 'FitsIn<int32_t>(value)' in src/coreclr/jit/compiler.hpp:2100 during 'Morph - Global'
Local HEAD DOTNET_JITMinOpts=1 FFFFFFFF
Shipping dotnet 11.0.0-preview.3.26207.106 (any config, Release) FFFFFFFF

Same regression window as #129076 (between preview-3 and HEAD); haven't bisected this one yet.

Asserts on osx-arm64 Checked at HEAD a8b2c92ce21. Whether Release builds produce wrong code is unverified — I don't have a Release runtime build handy. The assertion is at GenTreeIntCon::SetIconValue-style code path, which is normally a "load-bearing" invariant rather than a debug-only sanity check.

Required ingredients

All necessary, all sufficient when combined:

  1. BitOperations.RotateRight(0xFFFFFFFFu, k) for any k >= 1 (rotation count > 0)
  2. Result stored into a local
  3. Two uses of that local — one into a side-effecting target (here a static field), one as the return value

Removing any of these stops the crash. So:

  • Direct return BitOperations.RotateRight(0xFFFFFFFFu, 1); (single use, no local) — no crash, returns FFFFFFFF
  • Different constant input, e.g. BitOperations.RotateRight(0xFFFFFFFEu, 1) — no crash, returns 7FFFFFFF
  • ulong overload, BitOperations.RotateRight(0xFFFFFFFFFFFFFFFFul, 1) — no crash, returns FFFFFFFFFFFFFFFF

Hypothesis

The JIT recognizes BitOperations.RotateRight(uint, int) as an intrinsic and constant-folds it when both inputs are constants. The folded value is 0xFFFFFFFF. With two uses, CSE produces a shared constant node typed uint with value 0xFFFFFFFF. Something during Morph - Global then tries to write that constant value through a GenTreeIntCon::SetIconValue-style path with type == TYP_INT, which asserts FitsIn<int32_t>(value) and trips because 0xFFFFFFFF = 4294967295 > int.MaxValue = 2147483647.

The ulong-not-affected datapoint is consistent: that code path is gated on genTypeSize(type) <= genTypeSize(TYP_INT).

How it was found

ReifyCs (semantic-reification fuzzer, same one that found #129076) with a new --profile intrinsic populator that emits BitOperations.RotateLeft/Right and Math.Abs/Max/Min calls. Surfaced on the first 50-trial smoke campaign of that profile. Hand-reduced from a ~60-line generated function to the 6-line repro above.

Metadata

Metadata

Assignees

Labels

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

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