diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index bd572d7d70bd18..e42c0d84f9190d 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -285,13 +285,33 @@ interp_prev_ins (InterpInst *ins) return ins; } +static gboolean +check_stack_helper (TransformData *td, int n) +{ + int stack_size = GPTRDIFF_TO_INT (td->sp - td->stack); + if (stack_size < n) { + td->has_invalid_code = TRUE; + return FALSE; + } + return TRUE; +} + #define CHECK_STACK(td, n) \ do { \ - guint stack_size = GPTRDIFF_TO_UINT ((td)->sp - (td)->stack); \ - if (stack_size < (n)) \ - g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \ - m_class_get_name ((td)->method->klass), (td)->method->name, \ - stack_size, n, (td)->ip - (td)->il_code); \ + if (!check_stack_helper (td, n)) \ + goto exit; \ + } while (0) + +#define CHECK_STACK_RET_VOID(td, n) \ + do { \ + if (!check_stack_helper (td, n)) \ + return; \ + } while (0) + +#define CHECK_STACK_RET(td, n, ret) \ + do { \ + if (!check_stack_helper (td, n)) \ + return ret; \ } while (0) #define ENSURE_STACK_SIZE(td, size) \ @@ -872,9 +892,9 @@ handle_branch (TransformData *td, int long_op, int offset) static void one_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) { + CHECK_STACK_RET_VOID(td, 1); int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; int long_op = mint_op + type - STACK_TYPE_I4; - CHECK_STACK(td, 1); --td->sp; if (offset) { handle_branch (td, long_op, offset + inst_size); @@ -901,9 +921,9 @@ interp_add_conv (TransformData *td, StackInfo *sp, InterpInst *prev_ins, int typ static void two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) { + CHECK_STACK_RET_VOID(td, 2); int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type; int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type; - CHECK_STACK(td, 2); if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) { // The il instruction starts with the actual branch, and not with the conversion opcodes @@ -935,8 +955,8 @@ two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size) static void unary_arith_op(TransformData *td, int mint_op) { + CHECK_STACK_RET_VOID(td, 1); int op = mint_op + td->sp [-1].type - STACK_TYPE_I4; - CHECK_STACK(td, 1); td->sp--; interp_add_ins (td, op); interp_ins_set_sreg (td->last_ins, td->sp [0].local); @@ -947,6 +967,7 @@ unary_arith_op(TransformData *td, int mint_op) static void binary_arith_op(TransformData *td, int mint_op) { + CHECK_STACK_RET_VOID(td, 2); int type1 = td->sp [-2].type; int type2 = td->sp [-1].type; int op; @@ -978,7 +999,6 @@ binary_arith_op(TransformData *td, int mint_op) td->ip - td->il_code, mono_interp_opname (mint_op), type1, type2); } op = mint_op + type1 - STACK_TYPE_I4; - CHECK_STACK(td, 2); td->sp -= 2; interp_add_ins (td, op); interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local); @@ -989,8 +1009,8 @@ binary_arith_op(TransformData *td, int mint_op) static void shift_op(TransformData *td, int mint_op) { + CHECK_STACK_RET_VOID(td, 2); int op = mint_op + td->sp [-2].type - STACK_TYPE_I4; - CHECK_STACK(td, 2); if (td->sp [-1].type != STACK_TYPE_I4) { g_warning("%s.%s: shift type mismatch %d", m_class_get_name (td->method->klass), td->method->name, @@ -1079,7 +1099,7 @@ store_arg(TransformData *td, int n) { gint32 size = 0; int mt; - CHECK_STACK (td, 1); + CHECK_STACK_RET_VOID (td, 1); MonoType *type; type = get_arg_type_exact (td, n, &mt); @@ -1127,7 +1147,7 @@ static void store_local (TransformData *td, int local) { int mt = td->locals [local].mt; - CHECK_STACK (td, 1); + CHECK_STACK_RET_VOID (td, 1); #if SIZEOF_VOID_P == 8 // nint and int32 can be used interchangeably. Add implicit conversions. if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8) @@ -3132,7 +3152,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target if (target_method == NULL) { if (calli) { - CHECK_STACK(td, 1); + CHECK_STACK_RET(td, 1, FALSE); if (method->wrapper_type != MONO_WRAPPER_NONE) csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token); else { @@ -3300,7 +3320,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target need_null_check = TRUE; } - CHECK_STACK (td, csignature->param_count + csignature->hasthis); + CHECK_STACK_RET (td, csignature->param_count + csignature->hasthis, FALSE); if (tailcall && !td->gen_sdb_seq_points && !calli && op == -1 && (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 && @@ -4323,7 +4343,7 @@ initialize_clause_bblocks (TransformData *td) static void handle_ldind (TransformData *td, int op, int type, gboolean *volatile_) { - CHECK_STACK (td, 1); + CHECK_STACK_RET_VOID (td, 1); interp_add_ins (td, op); td->sp--; interp_ins_set_sreg (td->last_ins, td->sp [0].local); @@ -4340,7 +4360,7 @@ handle_ldind (TransformData *td, int op, int type, gboolean *volatile_) static void handle_stind (TransformData *td, int op, gboolean *volatile_) { - CHECK_STACK (td, 2); + CHECK_STACK_RET_VOID (td, 2); if (*volatile_) { interp_emit_memory_barrier (td, MONO_MEMORY_BARRIER_REL); *volatile_ = FALSE; @@ -4355,7 +4375,7 @@ handle_stind (TransformData *td, int op, gboolean *volatile_) static void handle_ldelem (TransformData *td, int op, int type) { - CHECK_STACK (td, 2); + CHECK_STACK_RET_VOID (td, 2); ENSURE_I4 (td, 1); interp_add_ins (td, op); td->sp -= 2; @@ -4368,7 +4388,7 @@ handle_ldelem (TransformData *td, int op, int type) static void handle_stelem (TransformData *td, int op) { - CHECK_STACK (td, 3); + CHECK_STACK_RET_VOID (td, 3); ENSURE_I4 (td, 2); interp_add_ins (td, op); td->sp -= 3; @@ -4589,7 +4609,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, td->dont_inline = g_list_prepend (td->dont_inline, method); while (td->ip < end) { - g_assert (td->sp >= td->stack); + // Check here for every opcode to avoid code bloat + if (td->has_invalid_code) + goto exit; in_offset = GPTRDIFF_TO_INT (td->ip - header->code); if (!inlining) td->current_il_offset = in_offset; @@ -7759,6 +7781,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, return ret; exit: ret = FALSE; + if (td->has_invalid_code) + mono_error_set_generic_error (error, "System", "InvalidProgramException", ""); goto exit_ret; } diff --git a/src/mono/mono/mini/interp/transform.h b/src/mono/mono/mini/interp/transform.h index 7ad00ab0b2618d..9c78df4fc5dacb 100644 --- a/src/mono/mono/mini/interp/transform.h +++ b/src/mono/mono/mini/interp/transform.h @@ -244,6 +244,7 @@ typedef struct // bail out of inlining when having to generate certain opcodes (like call, throw). int aggressive_inlining : 1; int optimized : 1; + int has_invalid_code : 1; } TransformData; #define STACK_TYPE_I4 0 diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 537f6c3dc59ce8..56897d76e578f4 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2207,9 +2207,6 @@ needs triage - - https://github.com/dotnet/runtime/issues/54395 - https://github.com/dotnet/runtime/issues/54396