diff --git a/src/coreclr/jit/rangecheck.h b/src/coreclr/jit/rangecheck.h index a722fa4bf06c09..70943ae69439a2 100644 --- a/src/coreclr/jit/rangecheck.h +++ b/src/coreclr/jit/rangecheck.h @@ -326,6 +326,16 @@ struct RangeOps static Range Add(const Range& r1, const Range& r2, bool unsignedAdd = false) { + if (unsignedAdd && + ((r1.IsConstantRange() && (r1.LowerLimit().GetConstant() < 0) && + (r1.UpperLimit().GetConstant() >= 0)) || + (r2.IsConstantRange() && (r2.LowerLimit().GetConstant() < 0) && + (r2.UpperLimit().GetConstant() >= 0)))) + { + // Signed intervals that straddle zero are not monotonic when interpreted as unsigned. + return Limit(Limit::keUnknown); + } + return ApplyRangeOp(r1, r2, [unsignedAdd](const Limit& a, const Limit& b) { // For Add we support: // keConstant + keConstant => keConstant @@ -340,7 +350,9 @@ struct RangeOps } static_assert(CheckedOps::Unsigned == true); - if (!CheckedOps::AddOverflows(a.GetConstant(), b.GetConstant(), unsignedAdd)) + if (!CheckedOps::AddOverflows(a.GetConstant(), b.GetConstant(), unsignedAdd) && + (!unsignedAdd || + !CheckedOps::AddOverflows(a.GetConstant(), b.GetConstant(), CheckedOps::Signed))) { if (a.IsConstant() && b.IsConstant()) { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_130431/Runtime_130431.cs b/src/tests/JIT/Regression/JitBlue/Runtime_130431/Runtime_130431.cs new file mode 100644 index 00000000000000..10e0d368629bc6 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_130431/Runtime_130431.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_130431 +{ + [Fact] + public static void TestEntryPoint() + { + Assert.Throws(() => Add(1, uint.MaxValue)); + Assert.Throws(() => AddWithSignStraddlingRange(uint.MaxValue, 1)); + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static uint Add(uint x, uint y) + { + uint result = checked(y + unchecked((byte)x)); + + if (x == 0) + { + return result + 1; + } + + return result; + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static uint AddWithSignStraddlingRange(uint x, uint y) + { + if (((int)x > 0) || (y > 1)) + { + return 0; + } + + return checked(x + y); + } +} diff --git a/src/tests/JIT/Regression/Regression_ro_2.csproj b/src/tests/JIT/Regression/Regression_ro_2.csproj index f768233f63c9b8..4a0ed731181667 100644 --- a/src/tests/JIT/Regression/Regression_ro_2.csproj +++ b/src/tests/JIT/Regression/Regression_ro_2.csproj @@ -113,6 +113,7 @@ +