[release/6.0] [mono] Fix a few corner case overflow operations (#58265)
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sat, 28 Aug 2021 08:07:53 +0000 (10:07 +0200)
committerGitHub <noreply@github.com>
Sat, 28 Aug 2021 08:07:53 +0000 (10:07 +0200)
Co-authored-by: Vlad Brezae <brezaevlad@gmail.com>
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/local-propagation.c
src/mono/mono/mini/mini-arm.c
src/mono/mono/mini/mini-mips.c
src/mono/mono/mini/mini-ppc.c
src/mono/mono/utils/mono-math.h
src/tests/issues.targets

index 623b7af..a79411b 100644 (file)
@@ -5476,33 +5476,29 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U8_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (mono_isnan (val) || mono_trunc (val) != (guint64)val)
+                       if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1])))
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], guint64) = (guint64)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U8_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (mono_isnan (val) || mono_trunc (val) != (guint64)val)
+                       if (!mono_try_trunc_u64 (val, (guint64*)(locals + ip [1])))
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], guint64) = (guint64)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I8_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (mono_isnan (val) || mono_trunc (val) != (gint64)val)
+                       if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1])))
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint64) = (gint64)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I8_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (mono_isnan (val) || mono_trunc (val) != (gint64)val)
+                       if (!mono_try_trunc_i64 (val, (gint64*)(locals + ip [1])))
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint64) = (gint64)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5804,17 +5800,20 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I4_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (mono_isnan (val) || mono_trunc (val) != (gint32)val)
+                       double val_r8 = (double)val;
+                       if (val_r8 > ((double)G_MININT32 - 1) && val_r8 < ((double)G_MAXINT32 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint32) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint32) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I4_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < G_MININT32 || val > G_MAXINT32 || isnan (val))
+                       if (val > ((double)G_MININT32 - 1) && val < ((double)G_MAXINT32 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint32) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint32)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5836,17 +5835,20 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U4_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (mono_isnan (val) || mono_trunc (val) != (guint32)val)
+                       double val_r8 = val;
+                       if (val_r8 > -1.0 && val_r8 < ((double)G_MAXUINT32 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint32)val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint32)val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U4_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < 0 || val > G_MAXUINT32 || isnan (val))
+                       if (val > -1.0 && val < ((double)G_MAXUINT32 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint32)val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint32) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5884,17 +5886,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I2_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (val < G_MININT16 || val > G_MAXINT16 || isnan (val))
+                       if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint16) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint16) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I2_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < G_MININT16 || val > G_MAXINT16 || isnan (val))
+                       if (val > (G_MININT16 - 1) && val < (G_MAXINT16 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint16) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint16) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5916,17 +5920,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U2_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (val < 0 || val > G_MAXUINT16 || isnan (val))
+                       if (val > -1.0f && val < (G_MAXUINT16 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint16) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint16) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U2_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < 0 || val > G_MAXUINT16 || isnan (val))
+                       if (val > -1.0 && val < (G_MAXUINT16 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint16) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint16) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5964,17 +5970,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I1_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (val < G_MININT8 || val > G_MAXINT8 || isnan (val))
+                       if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint8) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint8) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_I1_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < G_MININT8 || val > G_MAXINT8 || isnan (val))
+                       if (val > (G_MININT8 - 1) && val < (G_MAXINT8 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (gint8) val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (gint8) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
@@ -5996,17 +6004,19 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U1_R4) {
                        float val = LOCAL_VAR (ip [2], float);
-                       if (val < 0 || val > G_MAXUINT8 || isnan (val))
+                       if (val > -1.0f && val < (G_MAXUINT8 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint8)val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint8) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
                MINT_IN_CASE(MINT_CONV_OVF_U1_R8) {
                        double val = LOCAL_VAR (ip [2], double);
-                       if (val < 0 || val > G_MAXUINT8 || isnan (val))
+                       if (val > -1.0 && val < (G_MAXUINT8 + 1))
+                               LOCAL_VAR (ip [1], gint32) = (guint8)val;
+                       else
                                THROW_EX (mono_get_exception_overflow (), ip);
-                       LOCAL_VAR (ip [1], gint32) = (guint8) val;
                        ip += 3;
                        MINT_IN_BREAK;
                }
index 3bd878e..19801ed 100644 (file)
@@ -223,7 +223,7 @@ mono_strength_reduction_division (MonoCompile *cfg, MonoInst *ins)
                        guint32 tmp_regi;
 #endif
                        struct magic_signed mag;
-                       int power2 = mono_is_power_of_two (ins->inst_imm);
+                       int power2 = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1;
                        /* The decomposition doesn't handle exception throwing */
                        /* Optimization with MUL does not apply for -1, 0 and 1 divisors */
                        if (ins->inst_imm == 0 || ins->inst_imm == -1) {
@@ -350,7 +350,7 @@ mono_strength_reduction_ins (MonoCompile *cfg, MonoInst *ins, const char **spec)
                        ins->opcode = OP_INEG;
                } else if ((ins->opcode == OP_LMUL_IMM) && (ins->inst_imm == -1)) {
                        ins->opcode = OP_LNEG;
-               } else {
+               } else if (ins->inst_imm > 0) {
                        int power2 = mono_is_power_of_two (ins->inst_imm);
                        if (power2 >= 0) {
                                ins->opcode = (ins->opcode == OP_MUL_IMM) ? OP_SHL_IMM : ((ins->opcode == OP_LMUL_IMM) ? OP_LSHL_IMM : OP_ISHL_IMM);
index 58c0cef..f22ba5b 100644 (file)
@@ -3466,7 +3466,7 @@ loop_start:
                                ins->inst_c0 = 0;
                                break;
                        }
-                       imm8 = mono_is_power_of_two (ins->inst_imm);
+                       imm8 = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1;
                        if (imm8 > 0) {
                                ins->opcode = OP_SHL_IMM;
                                ins->inst_imm = imm8;
index 9a353ce..b77252e 100644 (file)
@@ -1987,7 +1987,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                                        MONO_DELETE_INS (bb, ins);
                                        continue;
                                }
-                       } else {
+                       } else if (ins->inst_imm > 0) {
                                int power2 = mono_is_power_of_two (ins->inst_imm);
                                if (power2 > 0) {
                                        ins->opcode = OP_SHL_IMM;
@@ -2666,7 +2666,7 @@ loop_start:
                                ins->inst_c0 = 0;
                                break;
                        }
-                       imm = mono_is_power_of_two (ins->inst_imm);
+                       imm = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1;
                        if (imm > 0) {
                                ins->opcode = OP_SHL_IMM;
                                ins->inst_imm = imm;
index 19097c9..e3de468 100644 (file)
@@ -1963,7 +1963,7 @@ mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
                                        MONO_DELETE_INS (bb, ins);
                                        continue;
                                }
-                       } else {
+                       } else if (inst->inst_imm > 0) {
                                int power2 = mono_is_power_of_two (ins->inst_imm);
                                if (power2 > 0) {
                                        ins->opcode = OP_SHL_IMM;
@@ -2537,7 +2537,7 @@ loop_start:
                                ins->inst_c0 = 0;
                                break;
                        }
-                       imm = mono_is_power_of_two (ins->inst_imm);
+                       imm = (ins->inst_imm > 0) ? mono_is_power_of_two (ins->inst_imm) : -1;
                        if (imm > 0) {
                                ins->opcode = OP_SHL_IMM;
                                ins->inst_imm = imm;
index 0f535e8..a24a0a3 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <math.h>
 #include <mono/utils/mono-publib.h>
+#include <glib.h>
 
 // Instead of isfinite, isinf, isnan, etc.,
 // use mono_isfininite, mono_isinf, mono_isnan, etc.
@@ -99,4 +100,27 @@ mono_round_to_even (double x)
        return copysign (floor_tmp, x);
 }
 
+static inline gboolean
+mono_try_trunc_i64 (double val, gint64 *out)
+{
+       const double two63  = 2147483648.0 * 4294967296.0;
+       // 0x402 is epsilon used to get us to the next value
+       if (val > (-two63 - 0x402) && val < two63) {
+               *out = (gint64)val;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static inline gboolean
+mono_try_trunc_u64 (double val, guint64 *out)
+{
+       const double two64  = 4294967296.0 * 4294967296.0;
+       if (val > -1.0 && val < two64) {
+               *out = (guint64)val;
+               return TRUE;
+       }
+       return FALSE;
+}
+
 #endif
index 85efa7c..29bf5fe 100644 (file)
         </ExcludeList>
 
 
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/Convert/value_numbering_checked_casts_of_constants/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/int64/misc/longmul/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/Convert/out_of_range_fp_to_int_conversions/*">
             <Issue>Mono does not define out of range fp to int conversions</Issue>
         </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/Overflow/FloatOvfToInt2_r/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/Overflow/FloatOvfToInt2_ro/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/Overflow/FloatOvfToInt2_d/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Methodical/Overflow/FloatOvfToInt2_do/*">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/JIT/opt/Devirtualization/Comparer_get_Default/*">
             <Issue>https://github.com/dotnet/runtime/issues/48190</Issue>
         </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/Convert/ldind_conv/**">
             <Issue>needs triage</Issue>
         </ExcludeList>
-        <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/Convert/signed_overflow_conversions_are_not_treated_as_unsigned/**">
-            <Issue>https://github.com/dotnet/runtime/issues/51323</Issue>
-        </ExcludeList>
         <ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/coverage/compiler/FilterToHandler/**">
             <Issue>needs triage</Issue>
         </ExcludeList>