Skip to content

Commit

Permalink
[valuetypes] use memcmp in default implementation of Equals for unali…
Browse files Browse the repository at this point in the history
…gned fields

some architectures (e.g. ARM) do not support reads of unaligned pointers

fixes mono#6320
  • Loading branch information
lewurm committed Jan 2, 2018
1 parent bf3d8ce commit 277a0a7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 8 deletions.
54 changes: 46 additions & 8 deletions mono/metadata/icall.c
Expand Up @@ -1162,40 +1162,77 @@ ves_icall_System_ValueType_Equals (MonoObject *this_obj, MonoObject *that, MonoA
continue;
if (mono_field_is_deleted (field))
continue;
guint8 *this_field = (guint8 *) this_obj + field->offset;
guint8 *that_field = (guint8 *) that + field->offset;

#ifdef NO_UNALIGNED_ACCESS
if (G_UNLIKELY ((intptr_t) this_field & 3 || (intptr_t) that_field & 3)) {

#define UNALIGNED_COMPARE(type) \
do { \
type left, right; \
memcpy (&left, this_field, sizeof (type)); \
memcpy (&right, that_field, sizeof (type)); \
if (left != right) \
return FALSE; \
} while (0);

switch (field->type->type) {
case MONO_TYPE_U2:
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
UNALIGNED_COMPARE (gint16);
break;
case MONO_TYPE_U4:
case MONO_TYPE_I4:
UNALIGNED_COMPARE (gint32);
break;
case MONO_TYPE_U8:
case MONO_TYPE_I8:
UNALIGNED_COMPARE (gint64);
break;
case MONO_TYPE_R4:
UNALIGNED_COMPARE (float);
case MONO_TYPE_R8:
UNALIGNED_COMPARE (double);
}
#undef UNALIGNED_CHECK
goto end_loop;
}
#endif

/* FIXME: Add more types */
switch (field->type->type) {
case MONO_TYPE_U1:
case MONO_TYPE_I1:
case MONO_TYPE_BOOLEAN:
if (*((guint8*)this_obj + field->offset) != *((guint8*)that + field->offset))
if (*this_field != *that_field)
return FALSE;
break;
case MONO_TYPE_U2:
case MONO_TYPE_I2:
case MONO_TYPE_CHAR:
if (*(gint16*)((guint8*)this_obj + field->offset) != *(gint16*)((guint8*)that + field->offset))
if (*(gint16 *) this_field != *(gint16 *) that_field)
return FALSE;
break;
case MONO_TYPE_U4:
case MONO_TYPE_I4:
if (*(gint32*)((guint8*)this_obj + field->offset) != *(gint32*)((guint8*)that + field->offset))
if (*(gint32 *) this_field != *(gint32 *) that_field)
return FALSE;
break;
case MONO_TYPE_U8:
case MONO_TYPE_I8:
if (*(gint64*)((guint8*)this_obj + field->offset) != *(gint64*)((guint8*)that + field->offset))
if (*(gint64 *) this_field != *(gint64 *) that_field)
return FALSE;
break;
case MONO_TYPE_R4:
if (*(float*)((guint8*)this_obj + field->offset) != *(float*)((guint8*)that + field->offset))
if (*(float *) this_field != *(float *) that_field)
return FALSE;
break;
case MONO_TYPE_R8:
if (*(double*)((guint8*)this_obj + field->offset) != *(double*)((guint8*)that + field->offset))
if (*(double *) this_field != *(double *) that_field)
return FALSE;
break;


case MONO_TYPE_STRING: {
MonoString *s1, *s2;
guint32 s1len, s2len;
Expand Down Expand Up @@ -1231,6 +1268,7 @@ ves_icall_System_ValueType_Equals (MonoObject *this_obj, MonoObject *that, MonoA
values [count++] = o;
}

end_loop:
if (klass->enumtype)
/* enums only have one non-static field */
break;
Expand Down
1 change: 1 addition & 0 deletions mono/tests/Makefile.am
Expand Up @@ -527,6 +527,7 @@ TESTS_CS_SRC= \
bug-58782-plain-throw.cs \
bug-58782-capture-and-throw.cs \
recursive-struct-arrays.cs \
struct-explicit-layout.cs \
bug-59281.cs \
init_array_with_lazy_type.cs \
weak-fields.cs \
Expand Down
21 changes: 21 additions & 0 deletions mono/tests/struct-explicit-layout.cs
@@ -0,0 +1,21 @@
using System;
using System.Runtime.InteropServices;

namespace Test {
[StructLayout ( LayoutKind.Explicit )]
public struct ST0 {
[FieldOffset(0)] public short S0;
[FieldOffset(2)] public int I0;
[FieldOffset(6)] public long L0;
[FieldOffset(14)] public float F0;
[FieldOffset(18)] public double D0;
}

public class Test {
public static int Main() {
ST0 s0, s1;
s0 = s1 = new ST0();
return s0.Equals (s1) ? 0 : 1;
}
}
}

0 comments on commit 277a0a7

Please sign in to comment.