Skip to content

Commit 5334107

Browse files
committed
[mono][interp] Always sign extend small integers to native integer when returning to compiled code
On amd64 it seems our jit expects i4 to be sign extended to the full 64bit register. On arm64 apple, unlike arm64 linux, callers of methods returning i1,u1,i2 or u2 are expecting a value sign extended to i4. In order to prevent any potential issues around this area, this commit takes on a conservative approach and sign extends every time, since there is no real cost to it. stackval_to_data_sign_ext is called either with a data pointer from a CallContext register or the address of a native int local variable in the `mini_get_interp_in_wrapper`. This means that it should always be safe to write the full value.
1 parent 27f527e commit 5334107

File tree

1 file changed

+44
-2
lines changed

1 file changed

+44
-2
lines changed

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

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,48 @@ stackval_to_data (MonoType *type, stackval *val, void *data, gboolean pinvoke)
985985
}
986986
}
987987

988+
static void
989+
stackval_to_data_sign_ext (MonoType *type, stackval *val, void *data, gboolean pinvoke)
990+
{
991+
switch (type->type) {
992+
case MONO_TYPE_I1: {
993+
mono_i *p = (mono_i*)data;
994+
*p = (mono_i)((gint8)val->data.i);
995+
break;
996+
}
997+
case MONO_TYPE_U1: {
998+
mono_u *p = (mono_u*)data;
999+
*p = (mono_u)((guint8)val->data.i);
1000+
break;
1001+
}
1002+
case MONO_TYPE_I2: {
1003+
mono_i *p = (mono_i*)data;
1004+
*p = (mono_i)((gint16)val->data.i);
1005+
break;
1006+
}
1007+
case MONO_TYPE_U2: {
1008+
mono_u *p = (mono_u*)data;
1009+
*p = (mono_u)((guint16)val->data.i);
1010+
break;
1011+
}
1012+
#if SIZEOF_VOID_P == 8
1013+
case MONO_TYPE_I4: {
1014+
mono_i *p = (mono_i*)data;
1015+
*p = (mono_i)(val->data.i);
1016+
break;
1017+
}
1018+
case MONO_TYPE_U4: {
1019+
mono_u *p = (mono_u*)data;
1020+
*p = (mono_u)((guint32)val->data.i);
1021+
break;
1022+
}
1023+
#endif
1024+
default:
1025+
stackval_to_data (type, val, data, pinvoke);
1026+
break;
1027+
}
1028+
}
1029+
9881030
typedef struct {
9891031
MonoException *ex;
9901032
MonoContext *ctx;
@@ -1651,7 +1693,7 @@ interp_frame_arg_to_data (MonoInterpFrameHandle frame, MonoMethodSignature *sig,
16511693

16521694
// If index == -1, we finished executing an InterpFrame and the result is at retval.
16531695
if (index == -1)
1654-
stackval_to_data (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled);
1696+
stackval_to_data_sign_ext (sig->ret, iframe->retval, data, sig->pinvoke && !sig->marshalling_disabled);
16551697
else if (sig->hasthis && index == 0)
16561698
*(gpointer*)data = iframe->stack->data.p;
16571699
else
@@ -2354,7 +2396,7 @@ interp_entry (InterpEntryData *data)
23542396
// The return value is at the bottom of the stack, after the locals space
23552397
type = rmethod->rtype;
23562398
if (type->type != MONO_TYPE_VOID)
2357-
stackval_to_data (type, frame.stack, data->res, FALSE);
2399+
stackval_to_data_sign_ext (type, frame.stack, data->res, FALSE);
23582400
}
23592401

23602402
static void

0 commit comments

Comments
 (0)