Skip to content

Commit 389cdbe

Browse files
authored
Fix setting or getting pointer fields with reflection (mono#20891)
Setting a pointer via reflection incorrectly added an extra layer of indirection, and getting a pointer via reflection incorrectly dereferenced the value once. As a result, setting and then getting only via reflection worked correctly, but doing either step by directly accessing the field and the other via reflection was broken. Also adjusts `FieldInfoTest` to test this, for both static and instance fields (the set path especially is different for those.) Fixes mono#20872 This change is released under the MIT license.
1 parent dbc5d75 commit 389cdbe

File tree

2 files changed

+49
-12
lines changed

2 files changed

+49
-12
lines changed

mcs/class/corlib/Test/System.Reflection/FieldInfoTest.cs

+48-2
Original file line numberDiff line numberDiff line change
@@ -536,25 +536,71 @@ public void GetValueOnConstantOfOpenGeneric ()
536536
public static unsafe void* ip;
537537

538538
[Test]
539-
public unsafe void GetSetValuePointers ()
539+
public unsafe void GetSetValuePointersStatic ()
540540
{
541541
Pointer p0 = (Pointer)typeof (FieldInfoTest).GetField ("ip").GetValue (null);
542542
int *p0i = (int*)Pointer.Unbox (p0);
543543
Assert.AreEqual (IntPtr.Zero, new IntPtr (p0i));
544544

545545
int i = 5;
546+
546547
void *p = &i;
547548
typeof (FieldInfoTest).GetField ("ip").SetValue (null, (IntPtr)p);
548-
Pointer p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip").GetValue (null);
549549

550+
Pointer p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip").GetValue (null);
550551
int *pi = (int*)Pointer.Unbox (p2);
551552
Assert.AreEqual (5, *pi);
552553

553554
typeof (FieldInfoTest).GetField ("ip").SetValue (null, (UIntPtr)p);
555+
554556
p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip").GetValue (null);
557+
pi = (int*)Pointer.Unbox (p2);
558+
Assert.AreEqual (5, *pi);
559+
560+
FieldInfoTest.ip = p;
555561

562+
p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip").GetValue (null);
556563
pi = (int*)Pointer.Unbox (p2);
557564
Assert.AreEqual (5, *pi);
565+
566+
typeof (FieldInfoTest).GetField ("ip").SetValue (null, (IntPtr)p);
567+
pi = (int*)FieldInfoTest.ip;
568+
Assert.AreEqual (5, *pi);
569+
}
570+
571+
public unsafe void* ip_inst;
572+
573+
[Test]
574+
public unsafe void GetSetValuePointersInstance ()
575+
{
576+
Pointer p0 = (Pointer)typeof (FieldInfoTest).GetField ("ip_inst").GetValue (this);
577+
int *p0i = (int*)Pointer.Unbox (p0);
578+
Assert.AreEqual (IntPtr.Zero, new IntPtr (p0i));
579+
580+
int i = 5;
581+
582+
void *p = &i;
583+
typeof (FieldInfoTest).GetField ("ip_inst").SetValue (this, (IntPtr)p);
584+
585+
Pointer p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip_inst").GetValue (this);
586+
int *pi = (int*)Pointer.Unbox (p2);
587+
Assert.AreEqual (5, *pi);
588+
589+
typeof (FieldInfoTest).GetField ("ip_inst").SetValue (this, (UIntPtr)p);
590+
591+
p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip_inst").GetValue (this);
592+
pi = (int*)Pointer.Unbox (p2);
593+
Assert.AreEqual (5, *pi);
594+
595+
this.ip_inst = p;
596+
597+
p2 = (Pointer)typeof (FieldInfoTest).GetField ("ip_inst").GetValue (this);
598+
pi = (int*)Pointer.Unbox (p2);
599+
Assert.AreEqual (5, *pi);
600+
601+
typeof (FieldInfoTest).GetField ("ip_inst").SetValue (this, (IntPtr)p);
602+
pi = (int*)this.ip_inst;
603+
Assert.AreEqual (5, *pi);
558604
}
559605

560606
[Test]

mono/metadata/object.c

+1-10
Original file line numberDiff line numberDiff line change
@@ -3415,11 +3415,7 @@ mono_field_set_value_internal (MonoObject *obj, MonoClassField *field, void *val
34153415
return;
34163416

34173417
dest = (char*)obj + field->offset;
3418-
#if ENABLE_NETCORE
34193418
mono_copy_value (field->type, dest, value, value && field->type->type == MONO_TYPE_PTR);
3420-
#else
3421-
mono_copy_value (field->type, dest, value, FALSE);
3422-
#endif
34233419
}
34243420

34253421
/**
@@ -3462,7 +3458,7 @@ mono_field_static_set_value_internal (MonoVTable *vt, MonoClassField *field, voi
34623458
} else {
34633459
dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
34643460
}
3465-
mono_copy_value (field->type, dest, value, FALSE);
3461+
mono_copy_value (field->type, dest, value, value && field->type->type == MONO_TYPE_PTR);
34663462
}
34673463

34683464
/**
@@ -3727,12 +3723,7 @@ mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field,
37273723
mono_field_get_value_internal (obj, field, v);
37283724
}
37293725

3730-
#if ENABLE_NETCORE
37313726
args [0] = ptr;
3732-
#else
3733-
/* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3734-
args [0] = ptr ? *ptr : NULL;
3735-
#endif
37363727
args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
37373728
goto_if_nok (error, return_null);
37383729

0 commit comments

Comments
 (0)