Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mono] Don't truncate the high bits when ldelema index is nint #73799

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 42 additions & 46 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,62 +1223,44 @@ ves_array_create (MonoClass *klass, int param_count, stackval *values, MonoError
return (MonoObject*) mono_array_new_full_checked (klass, lengths, lower_bounds, error);
}

static gint32
ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean safe)
static gsize
ves_array_calculate_index (MonoArray *ao, stackval *sp, gboolean native_int)
{
MonoClass *ac = ((MonoObject *) ao)->vtable->klass;

guint32 pos = 0;
gsize pos = 0;
if (ao->bounds) {
for (gint32 i = 0; i < m_class_get_rank (ac); i++) {
gint32 idx = sp [i].data.i;
gint32 lower = ao->bounds [i].lower_bound;
guint32 len = ao->bounds [i].length;
if (safe && (idx < lower || (guint32)(idx - lower) >= len))
if (idx < lower || (guint32)(idx - lower) >= len)
return -1;
pos = (pos * len) + (guint32)(idx - lower);
}
} else {
pos = sp [0].data.i;
if (safe && pos >= ao->max_length)
if (native_int)
pos = sp [0].data.nati;
else
pos = (gsize)sp [0].data.i;
if (pos >= ao->max_length)
return -1;
}
return pos;
}

static MonoException*
ves_array_get (InterpFrame *frame, stackval *sp, stackval *retval, MonoMethodSignature *sig, gboolean safe)
{
MonoObject *o = sp->data.o;
MonoArray *ao = (MonoArray *) o;
MonoClass *ac = o->vtable->klass;

g_assert (m_class_get_rank (ac) >= 1);

gint32 pos = ves_array_calculate_index (ao, sp + 1, safe);
if (pos == -1)
return mono_get_exception_index_out_of_range ();

gint32 esize = mono_array_element_size (ac);
gconstpointer ea = mono_array_addr_with_size_fast (ao, esize, pos);

MonoType *mt = sig->ret;
stackval_from_data (mt, retval, ea, FALSE);
return NULL;
}

static MonoException*
ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, gpointer *ret, stackval *sp, gboolean needs_typecheck)
ves_array_element_address (InterpFrame *frame, MonoClass *required_type, MonoArray *ao, gpointer *ret, stackval *sp, gboolean native_int)
{
MonoClass *ac = ((MonoObject *) ao)->vtable->klass;

g_assert (m_class_get_rank (ac) >= 1);

gint32 pos = ves_array_calculate_index (ao, sp, TRUE);
gsize pos = ves_array_calculate_index (ao, sp, native_int);
if (pos == -1)
return mono_get_exception_index_out_of_range ();

if (needs_typecheck && !mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
if (!mono_class_is_assignable_from_internal (m_class_get_element_class (mono_object_class ((MonoObject *) ao)), required_type))
return mono_get_exception_array_type_mismatch ();
gint32 esize = mono_array_element_size (ac);
*ret = mono_array_addr_with_size_fast (ao, esize, pos);
Expand Down Expand Up @@ -3529,6 +3511,19 @@ static long total_executed_opcodes;

#define LOCAL_VAR(offset,type) (*(type*)(locals + (offset)))

static MONO_ALWAYS_INLINE gsize
get_array_offset (unsigned char *locals, guint16 var_offset, gboolean native_int)
{
#if SIZEOF_VOID_P == 8
if (native_int)
return LOCAL_VAR (var_offset, gsize);
else
return (gsize)LOCAL_VAR (var_offset, guint32);
#else
return LOCAL_VAR (var_offset, gsize);
#endif
}

/*
* If CLAUSE_ARGS is non-null, start executing from it.
* The ERROR argument is used to avoid declaring an error object for every interp frame, its not used
Expand Down Expand Up @@ -6102,12 +6097,12 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
/* No bounds, one direction */
MonoArray *ao = LOCAL_VAR (ip [2], MonoArray*);
NULL_CHECK (ao);
guint32 index = LOCAL_VAR (ip [3], guint32);
gsize index = get_array_offset (locals, ip [3], ip [5]);
if (index >= ao->max_length)
THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip);
guint16 size = ip [4];
LOCAL_VAR (ip [1], gpointer) = mono_array_addr_with_size_fast (ao, size, index);
ip += 5;
ip += 6;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_LDELEMA) {
Expand All @@ -6119,7 +6114,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
NULL_CHECK (ao);

g_assert (ao->bounds);
guint32 pos = 0;
gsize pos = 0;
for (int i = 0; i < rank; i++) {
gint32 idx = sp [i + 1].data.i;
gint32 lower = ao->bounds [i].lower_bound;
Expand All @@ -6140,22 +6135,23 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MonoObject *o = (MonoObject*) sp [0].data.o;
NULL_CHECK (o);

gboolean native_int = ip [4];
MonoClass *klass = (MonoClass*)frame->imethod->data_items [ip [3]];
MonoException *address_ex = ves_array_element_address (frame, klass, (MonoArray *) o, (gpointer*)(locals + ip [1]), sp + 1, TRUE);
MonoException *address_ex = ves_array_element_address (frame, klass, (MonoArray *) o, (gpointer*)(locals + ip [1]), sp + 1, native_int);
if (address_ex)
THROW_EX (address_ex, ip);
ip += 4;
ip += 5;
MINT_IN_BREAK;
}

#define LDELEM(datatype,elemtype) do { \
MonoArray *o = LOCAL_VAR (ip [2], MonoArray*); \
NULL_CHECK (o); \
guint32 aindex = LOCAL_VAR (ip [3], guint32); \
gsize aindex = get_array_offset (locals, ip [3], ip [4]); \
if (aindex >= mono_array_length_internal (o)) \
THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); \
LOCAL_VAR (ip [1], datatype) = mono_array_get_fast (o, elemtype, aindex); \
ip += 4; \
ip += 5; \
} while (0)
MINT_IN_CASE(MINT_LDELEM_I1) LDELEM(gint32, gint8); MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDELEM_U1) LDELEM(gint32, guint8); MINT_IN_BREAK;
Expand All @@ -6171,31 +6167,31 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_CASE(MINT_LDELEM_VT) {
MonoArray *o = LOCAL_VAR (ip [2], MonoArray*);
NULL_CHECK (o);
mono_u aindex = LOCAL_VAR (ip [3], gint32);
gsize aindex = get_array_offset (locals, ip [3], ip [5]);
if (aindex >= mono_array_length_internal (o))
THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip);

guint16 size = ip [4];
char *src_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex);
memcpy (locals + ip [1], src_addr, size);

ip += 5;
ip += 6;
MINT_IN_BREAK;
}
#define STELEM_PROLOG(o, aindex) do { \
o = LOCAL_VAR (ip [1], MonoArray*); \
NULL_CHECK (o); \
aindex = LOCAL_VAR (ip [2], gint32); \
aindex = get_array_offset (locals, ip [2], ip [4]); \
if (aindex >= mono_array_length_internal (o)) \
THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip); \
} while (0)

#define STELEM(datatype, elemtype) do { \
MonoArray *o; \
guint32 aindex; \
gsize aindex; \
STELEM_PROLOG(o, aindex); \
mono_array_set_fast (o, elemtype, aindex, LOCAL_VAR (ip [3], datatype)); \
ip += 4; \
ip += 5; \
} while (0)
MINT_IN_CASE(MINT_STELEM_I1) STELEM(gint32, gint8); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STELEM_U1) STELEM(gint32, guint8); MINT_IN_BREAK;
Expand All @@ -6208,7 +6204,7 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STELEM_R8) STELEM(double, double); MINT_IN_BREAK;
MINT_IN_CASE(MINT_STELEM_REF) {
MonoArray *o;
guint32 aindex;
gsize aindex;
STELEM_PROLOG(o, aindex);
MonoObject *ref = LOCAL_VAR (ip [3], MonoObject*);

Expand All @@ -6219,22 +6215,22 @@ MINT_IN_CASE(MINT_BRTRUE_I8_SP) ZEROP_SP(gint64, !=); MINT_IN_BREAK;
THROW_EX (interp_get_exception_array_type_mismatch (frame, ip), ip);
}
mono_array_setref_fast ((MonoArray *) o, aindex, ref);
ip += 4;
ip += 5;
MINT_IN_BREAK;
}

MINT_IN_CASE(MINT_STELEM_VT) {
MonoArray *o = LOCAL_VAR (ip [1], MonoArray*);
NULL_CHECK (o);
guint32 aindex = LOCAL_VAR (ip [2], guint32);
gsize aindex = get_array_offset (locals, ip [2], ip [6]);
if (aindex >= mono_array_length_internal (o))
THROW_EX (interp_get_exception_index_out_of_range (frame, ip), ip);

guint16 size = ip [5];
char *dst_addr = mono_array_addr_with_size_fast ((MonoArray *) o, size, aindex);
MonoClass *klass_vt = (MonoClass*)frame->imethod->data_items [ip [4]];
mono_value_copy_internal (dst_addr, locals + ip [3], klass_vt);
ip += 6;
ip += 7;
MINT_IN_BREAK;
}
MINT_IN_CASE(MINT_CONV_OVF_I4_U4) {
Expand Down
54 changes: 27 additions & 27 deletions src/mono/mono/mini/interp/mintops.def
Original file line number Diff line number Diff line change
Expand Up @@ -375,34 +375,34 @@ OPDEF(MINT_LOCALLOC, "localloc", 3, 1, 1, MintOpNoArgs)
OPDEF(MINT_INITLOCAL, "initlocal", 3, 1, 0, MintOpShortInt)
OPDEF(MINT_INITLOCALS, "initlocals", 3, 0, 0, MintOpTwoShorts)

OPDEF(MINT_LDELEM_I, "ldelem.i", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I1, "ldelem.i1", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U1, "ldelem.u1", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I2, "ldelem.i2", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U2, "ldelem.u2", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I4, "ldelem.i4", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U4, "ldelem.u4", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I8, "ldelem.i8", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_R4, "ldelem.r4", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_R8, "ldelem.r8", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_REF, "ldelem.ref", 4, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_VT, "ldelem.vt", 5, 1, 2, MintOpShortInt)

OPDEF(MINT_LDELEMA1, "ldelema1", 5, 1, 2, MintOpShortInt)
OPDEF(MINT_LDELEM_I, "ldelem.i", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I1, "ldelem.i1", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U1, "ldelem.u1", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I2, "ldelem.i2", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U2, "ldelem.u2", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I4, "ldelem.i4", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_U4, "ldelem.u4", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_I8, "ldelem.i8", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_R4, "ldelem.r4", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_R8, "ldelem.r8", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_REF, "ldelem.ref", 5, 1, 2, MintOpNoArgs)
OPDEF(MINT_LDELEM_VT, "ldelem.vt", 6, 1, 2, MintOpShortInt)

OPDEF(MINT_LDELEMA1, "ldelema1", 6, 1, 2, MintOpShortInt)
OPDEF(MINT_LDELEMA, "ldelema", 5, 1, 1, MintOpTwoShorts)
OPDEF(MINT_LDELEMA_TC, "ldelema.tc", 4, 1, 1, MintOpTwoShorts)

OPDEF(MINT_STELEM_I, "stelem.i", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I1, "stelem.i1", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_U1, "stelem.u1", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I2, "stelem.i2", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_U2, "stelem.u2", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I4, "stelem.i4", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I8, "stelem.i8", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_R4, "stelem.r4", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_R8, "stelem.r8", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_REF, "stelem.ref", 4, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_VT, "stelem.vt", 6, 0, 3, MintOpTwoShorts)
OPDEF(MINT_LDELEMA_TC, "ldelema.tc", 5, 1, 1, MintOpTwoShorts)

OPDEF(MINT_STELEM_I, "stelem.i", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I1, "stelem.i1", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_U1, "stelem.u1", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I2, "stelem.i2", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_U2, "stelem.u2", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I4, "stelem.i4", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_I8, "stelem.i8", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_R4, "stelem.r4", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_R8, "stelem.r8", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_REF, "stelem.ref", 5, 0, 3, MintOpNoArgs)
OPDEF(MINT_STELEM_VT, "stelem.vt", 7, 0, 3, MintOpTwoShorts)

OPDEF(MINT_LDLEN, "ldlen", 3, 1, 1, MintOpNoArgs)
OPDEF(MINT_LDLEN_SPAN, "ldlen.span", 4, 1, 1, MintOpShortInt)
Expand Down
21 changes: 16 additions & 5 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -4253,23 +4253,25 @@ static void
handle_ldelem (TransformData *td, int op, int type)
{
CHECK_STACK (td, 2);
ENSURE_I4 (td, 1);
gboolean native_int = td->sp [-1].type != STACK_TYPE_I4;
interp_add_ins (td, op);
td->sp -= 2;
interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
push_simple_type (td, type);
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
td->last_ins->data [0] = native_int;
++td->ip;
}

static void
handle_stelem (TransformData *td, int op)
{
CHECK_STACK (td, 3);
ENSURE_I4 (td, 2);
gboolean native_int = td->sp [-2].type != STACK_TYPE_I4;
interp_add_ins (td, op);
td->sp -= 3;
interp_ins_set_sregs3 (td->last_ins, td->sp [0].local, td->sp [1].local, td->sp [2].local);
td->last_ins->data [0] = native_int;
++td->ip;
}

Expand Down Expand Up @@ -6308,7 +6310,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
case CEE_LDELEMA: {
gint32 size;
CHECK_STACK (td, 2);
ENSURE_I4 (td, 1);
token = read32 (td->ip + 1);

if (method->wrapper_type != MONO_WRAPPER_NONE)
Expand All @@ -6318,6 +6319,8 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,

CHECK_TYPELOAD (klass);

gboolean native_int = td->sp [-1].type != STACK_TYPE_I4;

if (!m_class_is_valuetype (klass) && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
/*
* Check the class for failures before the type check, which can
Expand All @@ -6334,6 +6337,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
push_simple_type (td, STACK_TYPE_MP);
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
td->last_ins->data [0] = get_data_item_index (td, klass);
td->last_ins->data [1] = native_int;
td->last_ins->info.call_args = call_args;
interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG);
td->last_ins->flags |= INTERP_INST_FLAG_CALL;
Expand All @@ -6346,6 +6350,7 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
mono_class_init_internal (klass);
size = mono_class_array_element_size (klass);
td->last_ins->data [0] = GINT32_TO_UINT16 (size);
td->last_ins->data [1] = native_int;
}

readonly = FALSE;
Expand Down Expand Up @@ -6423,13 +6428,14 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
g_assert (size < G_MAXUINT16);

CHECK_STACK (td, 2);
ENSURE_I4 (td, 1);
gboolean native_int = td->sp [-1].type != STACK_TYPE_I4;
interp_add_ins (td, MINT_LDELEM_VT);
td->sp -= 2;
interp_ins_set_sregs2 (td->last_ins, td->sp [0].local, td->sp [1].local);
push_type_vt (td, klass, size);
interp_ins_set_dreg (td->last_ins, td->sp [-1].local);
td->last_ins->data [0] = GINT_TO_UINT16 (size);
td->last_ins->data [1] = native_int;
++td->ip;
break;
}
Expand Down Expand Up @@ -6504,9 +6510,14 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header,
int size = mono_class_value_size (klass, NULL);
g_assert (size < G_MAXUINT16);

handle_stelem (td, MINT_STELEM_VT);
gboolean native_int = td->sp [-2].type != STACK_TYPE_I4;
interp_add_ins (td, MINT_STELEM_VT);
td->sp -= 3;
interp_ins_set_sregs3 (td->last_ins, td->sp [0].local, td->sp [1].local, td->sp [2].local);
td->last_ins->data [0] = get_data_item_index (td, klass);
td->last_ins->data [1] = GINT_TO_UINT16 (size);
td->last_ins->data [2] = native_int;
td->ip++;
break;
}
default: {
Expand Down
11 changes: 10 additions & 1 deletion src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -4216,7 +4216,16 @@ mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, Mono
mult_reg = alloc_preg (cfg);
array_reg = arr->dreg;

realidx2_reg = index2_reg = mini_emit_sext_index_reg (cfg, index);
if (TARGET_SIZEOF_VOID_P == 8) {
// If index is not I4 don't sign extend otherwise we lose high word
if (index->type == STACK_I4)
index2_reg = mini_emit_sext_index_reg (cfg, index);
else
index2_reg = index->dreg;
} else {
index2_reg = index->dreg;
}
realidx2_reg = index2_reg;

if (bounded) {
bounds_reg = alloc_preg (cfg);
Expand Down
Loading