Skip to content

Commit b5da2c6

Browse files
authored
[mono][interp] Throw invalid program if stack state is invalid (#73215)
Rather than printing warning and then overflowing the stack info buffer. Store error in TransformData to reduce code size.
1 parent 705e071 commit b5da2c6

File tree

3 files changed

+44
-22
lines changed

3 files changed

+44
-22
lines changed

src/mono/mono/mini/interp/transform.c

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,33 @@ interp_prev_ins (InterpInst *ins)
289289
return ins;
290290
}
291291

292+
static gboolean
293+
check_stack_helper (TransformData *td, int n)
294+
{
295+
int stack_size = GPTRDIFF_TO_INT (td->sp - td->stack);
296+
if (stack_size < n) {
297+
td->has_invalid_code = TRUE;
298+
return FALSE;
299+
}
300+
return TRUE;
301+
}
302+
292303
#define CHECK_STACK(td, n) \
293304
do { \
294-
guint stack_size = GPTRDIFF_TO_UINT ((td)->sp - (td)->stack); \
295-
if (stack_size < (n)) \
296-
g_warning ("%s.%s: not enough values (%d < %d) on stack at %04x", \
297-
m_class_get_name ((td)->method->klass), (td)->method->name, \
298-
stack_size, n, (td)->ip - (td)->il_code); \
305+
if (!check_stack_helper (td, n)) \
306+
goto exit; \
307+
} while (0)
308+
309+
#define CHECK_STACK_RET_VOID(td, n) \
310+
do { \
311+
if (!check_stack_helper (td, n)) \
312+
return; \
313+
} while (0)
314+
315+
#define CHECK_STACK_RET(td, n, ret) \
316+
do { \
317+
if (!check_stack_helper (td, n)) \
318+
return ret; \
299319
} while (0)
300320

301321
#define ENSURE_STACK_SIZE(td, size) \
@@ -876,9 +896,9 @@ handle_branch (TransformData *td, int long_op, int offset)
876896
static void
877897
one_arg_branch(TransformData *td, int mint_op, int offset, int inst_size)
878898
{
899+
CHECK_STACK_RET_VOID(td, 1);
879900
int type = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
880901
int long_op = mint_op + type - STACK_TYPE_I4;
881-
CHECK_STACK(td, 1);
882902
--td->sp;
883903
if (offset) {
884904
handle_branch (td, long_op, offset + inst_size);
@@ -905,9 +925,9 @@ interp_add_conv (TransformData *td, StackInfo *sp, InterpInst *prev_ins, int typ
905925
static void
906926
two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size)
907927
{
928+
CHECK_STACK_RET_VOID(td, 2);
908929
int type1 = td->sp [-1].type == STACK_TYPE_O || td->sp [-1].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-1].type;
909930
int type2 = td->sp [-2].type == STACK_TYPE_O || td->sp [-2].type == STACK_TYPE_MP ? STACK_TYPE_I : td->sp [-2].type;
910-
CHECK_STACK(td, 2);
911931

912932
if (type1 == STACK_TYPE_I4 && type2 == STACK_TYPE_I8) {
913933
// The il instruction starts with the actual branch, and not with the conversion opcodes
@@ -939,8 +959,8 @@ two_arg_branch(TransformData *td, int mint_op, int offset, int inst_size)
939959
static void
940960
unary_arith_op(TransformData *td, int mint_op)
941961
{
962+
CHECK_STACK_RET_VOID(td, 1);
942963
int op = mint_op + td->sp [-1].type - STACK_TYPE_I4;
943-
CHECK_STACK(td, 1);
944964
td->sp--;
945965
interp_add_ins (td, op);
946966
interp_ins_set_sreg (td->last_ins, td->sp [0].local);
@@ -951,6 +971,7 @@ unary_arith_op(TransformData *td, int mint_op)
951971
static void
952972
binary_arith_op(TransformData *td, int mint_op)
953973
{
974+
CHECK_STACK_RET_VOID(td, 2);
954975
int type1 = td->sp [-2].type;
955976
int type2 = td->sp [-1].type;
956977
int op;
@@ -982,7 +1003,6 @@ binary_arith_op(TransformData *td, int mint_op)
9821003
td->ip - td->il_code, mono_interp_opname (mint_op), type1, type2);
9831004
}
9841005
op = mint_op + type1 - STACK_TYPE_I4;
985-
CHECK_STACK(td, 2);
9861006
td->sp -= 2;
9871007
interp_add_ins (td, op);
9881008
interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
@@ -993,8 +1013,8 @@ binary_arith_op(TransformData *td, int mint_op)
9931013
static void
9941014
shift_op(TransformData *td, int mint_op)
9951015
{
1016+
CHECK_STACK_RET_VOID(td, 2);
9961017
int op = mint_op + td->sp [-2].type - STACK_TYPE_I4;
997-
CHECK_STACK(td, 2);
9981018
if (td->sp [-1].type != STACK_TYPE_I4) {
9991019
g_warning("%s.%s: shift type mismatch %d",
10001020
m_class_get_name (td->method->klass), td->method->name,
@@ -1083,7 +1103,7 @@ store_arg(TransformData *td, int n)
10831103
{
10841104
gint32 size = 0;
10851105
int mt;
1086-
CHECK_STACK (td, 1);
1106+
CHECK_STACK_RET_VOID (td, 1);
10871107
MonoType *type;
10881108

10891109
type = get_arg_type_exact (td, n, &mt);
@@ -1131,7 +1151,7 @@ static void
11311151
store_local (TransformData *td, int local)
11321152
{
11331153
int mt = td->locals [local].mt;
1134-
CHECK_STACK (td, 1);
1154+
CHECK_STACK_RET_VOID (td, 1);
11351155
#if SIZEOF_VOID_P == 8
11361156
// nint and int32 can be used interchangeably. Add implicit conversions.
11371157
if (td->sp [-1].type == STACK_TYPE_I4 && stack_type [mt] == STACK_TYPE_I8)
@@ -3121,7 +3141,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
31213141

31223142
if (target_method == NULL) {
31233143
if (calli) {
3124-
CHECK_STACK(td, 1);
3144+
CHECK_STACK_RET(td, 1, FALSE);
31253145
if (method->wrapper_type != MONO_WRAPPER_NONE)
31263146
csignature = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
31273147
else {
@@ -3289,7 +3309,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
32893309
need_null_check = TRUE;
32903310
}
32913311

3292-
CHECK_STACK (td, csignature->param_count + csignature->hasthis);
3312+
CHECK_STACK_RET (td, csignature->param_count + csignature->hasthis, FALSE);
32933313
if (tailcall && !td->gen_sdb_seq_points && !calli && op == -1 &&
32943314
(target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 &&
32953315
(target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 &&
@@ -4312,7 +4332,7 @@ initialize_clause_bblocks (TransformData *td)
43124332
static void
43134333
handle_ldind (TransformData *td, int op, int type, gboolean *volatile_)
43144334
{
4315-
CHECK_STACK (td, 1);
4335+
CHECK_STACK_RET_VOID (td, 1);
43164336
interp_add_ins (td, op);
43174337
td->sp--;
43184338
interp_ins_set_sreg (td->last_ins, td->sp [0].local);
@@ -4329,7 +4349,7 @@ handle_ldind (TransformData *td, int op, int type, gboolean *volatile_)
43294349
static void
43304350
handle_stind (TransformData *td, int op, gboolean *volatile_)
43314351
{
4332-
CHECK_STACK (td, 2);
4352+
CHECK_STACK_RET_VOID (td, 2);
43334353
if (*volatile_) {
43344354
interp_emit_memory_barrier (td, MONO_MEMORY_BARRIER_REL);
43354355
*volatile_ = FALSE;
@@ -4344,7 +4364,7 @@ handle_stind (TransformData *td, int op, gboolean *volatile_)
43444364
static void
43454365
handle_ldelem (TransformData *td, int op, int type)
43464366
{
4347-
CHECK_STACK (td, 2);
4367+
CHECK_STACK_RET_VOID (td, 2);
43484368
ENSURE_I4 (td, 1);
43494369
interp_add_ins (td, op);
43504370
td->sp -= 2;
@@ -4357,7 +4377,7 @@ handle_ldelem (TransformData *td, int op, int type)
43574377
static void
43584378
handle_stelem (TransformData *td, int op)
43594379
{
4360-
CHECK_STACK (td, 3);
4380+
CHECK_STACK_RET_VOID (td, 3);
43614381
ENSURE_I4 (td, 2);
43624382
interp_add_ins (td, op);
43634383
td->sp -= 3;
@@ -4578,7 +4598,9 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
45784598

45794599
td->dont_inline = g_list_prepend (td->dont_inline, method);
45804600
while (td->ip < end) {
4581-
g_assert (td->sp >= td->stack);
4601+
// Check here for every opcode to avoid code bloat
4602+
if (td->has_invalid_code)
4603+
goto exit;
45824604
in_offset = GPTRDIFF_TO_INT (td->ip - header->code);
45834605
if (!inlining)
45844606
td->current_il_offset = in_offset;
@@ -7750,6 +7772,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
77507772
return ret;
77517773
exit:
77527774
ret = FALSE;
7775+
if (td->has_invalid_code)
7776+
mono_error_set_generic_error (error, "System", "InvalidProgramException", "");
77537777
goto exit_ret;
77547778
}
77557779

src/mono/mono/mini/interp/transform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ typedef struct
244244
// bail out of inlining when having to generate certain opcodes (like call, throw).
245245
int aggressive_inlining : 1;
246246
int optimized : 1;
247+
int has_invalid_code : 1;
247248
} TransformData;
248249

249250
#define STACK_TYPE_I4 0

src/tests/issues.targets

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,9 +2213,6 @@
22132213
<ExcludeList Include = "$(XunitTestBinBase)/JIT/Methodical/ELEMENT_TYPE_IU/u_fld_il_d/**">
22142214
<Issue>needs triage</Issue>
22152215
</ExcludeList>
2216-
<ExcludeList Include = "$(XunitTestBinBase)/JIT/jit64/localloc/ehverify/eh07_large/**">
2217-
<Issue>https://github.com/dotnet/runtime/issues/54395</Issue>
2218-
</ExcludeList>
22192216
<ExcludeList Include = "$(XunitTestBinBase)/JIT/jit64/verif/sniff/fg/ver_fg_13/**">
22202217
<Issue>https://github.com/dotnet/runtime/issues/54396</Issue>
22212218
</ExcludeList>

0 commit comments

Comments
 (0)