1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6//
7////////////////////////////////////////////////////////////////////////////////
8// This module defines a Utility Class used by reflection
9//
10//
11
12////////////////////////////////////////////////////////////////////////////////
13
14
15#include "common.h"
16#include "invokeutil.h"
17#include "corpriv.h"
18#include "method.hpp"
19#include "threads.h"
20#include "excep.h"
21#include "field.h"
22#include "customattribute.h"
23#include "eeconfig.h"
24#include "generics.h"
25#include "runtimehandles.h"
26#include "argdestination.h"
27
28#ifndef CROSSGEN_COMPILE
29
30// The Attributes Table
31// 20 bits for built in types and 12 bits for Properties
32// The properties are followed by the widening mask. All types widen to them selves.
33const DWORD InvokeUtil::PrimitiveAttributes[PRIMITIVE_TABLE_SIZE] = {
34 0x00, // ELEMENT_TYPE_END
35 0x00, // ELEMENT_TYPE_VOID
36 PT_Primitive | 0x0004, // ELEMENT_TYPE_BOOLEAN
37 PT_Primitive | 0x3F88, // ELEMENT_TYPE_CHAR (W = U2, CHAR, I4, U4, I8, U8, R4, R8) (U2 == Char)
38 PT_Primitive | 0x3550, // ELEMENT_TYPE_I1 (W = I1, I2, I4, I8, R4, R8)
39 PT_Primitive | 0x3FE8, // ELEMENT_TYPE_U1 (W = CHAR, U1, I2, U2, I4, U4, I8, U8, R4, R8)
40 PT_Primitive | 0x3540, // ELEMENT_TYPE_I2 (W = I2, I4, I8, R4, R8)
41 PT_Primitive | 0x3F88, // ELEMENT_TYPE_U2 (W = U2, CHAR, I4, U4, I8, U8, R4, R8)
42 PT_Primitive | 0x3500, // ELEMENT_TYPE_I4 (W = I4, I8, R4, R8)
43 PT_Primitive | 0x3E00, // ELEMENT_TYPE_U4 (W = U4, I8, R4, R8)
44 PT_Primitive | 0x3400, // ELEMENT_TYPE_I8 (W = I8, R4, R8)
45 PT_Primitive | 0x3800, // ELEMENT_TYPE_U8 (W = U8, R4, R8)
46 PT_Primitive | 0x3000, // ELEMENT_TYPE_R4 (W = R4, R8)
47 PT_Primitive | 0x2000, // ELEMENT_TYPE_R8 (W = R8)
48};
49
50BOOL InvokeUtil::IsVoidPtr(TypeHandle th)
51{
52 LIMITED_METHOD_CONTRACT;
53
54 if (!th.IsPointer())
55 return FALSE;
56
57 return th.AsTypeDesc()->GetTypeParam() == MscorlibBinder::GetElementType(ELEMENT_TYPE_VOID);
58}
59
60OBJECTREF InvokeUtil::CreatePointer(TypeHandle th, void * p)
61{
62 CONTRACT(OBJECTREF) {
63 THROWS;
64 GC_TRIGGERS;
65 MODE_COOPERATIVE;
66 PRECONDITION(!th.IsNull());
67 POSTCONDITION(RETVAL != NULL);
68 }
69 CONTRACT_END;
70
71 OBJECTREF refObj = NULL;
72 GCPROTECT_BEGIN(refObj);
73
74 refObj = AllocateObject(MscorlibBinder::GetClass(CLASS__POINTER));
75
76 ((ReflectionPointer *)OBJECTREFToObject(refObj))->_ptr = p;
77
78 OBJECTREF refType = th.GetManagedClassObject();
79 SetObjectReference(&(((ReflectionPointer *)OBJECTREFToObject(refObj))->_ptrType), refType, GetAppDomain());
80
81 GCPROTECT_END();
82 RETURN refObj;
83}
84
85TypeHandle InvokeUtil::GetPointerType(OBJECTREF pObj) {
86 CONTRACT(TypeHandle) {
87 NOTHROW;
88 GC_NOTRIGGER;
89 MODE_COOPERATIVE;
90 PRECONDITION(pObj != NULL);
91 POSTCONDITION(!RETVAL.IsNull());
92 }
93 CONTRACT_END;
94
95 ReflectionPointer * pReflectionPointer = (ReflectionPointer *)OBJECTREFToObject(pObj);
96 REFLECTCLASSBASEREF o = (REFLECTCLASSBASEREF)pReflectionPointer->_ptrType;
97 TypeHandle typeHandle = o->GetType();
98 RETURN typeHandle;
99}
100
101void* InvokeUtil::GetPointerValue(OBJECTREF pObj) {
102 CONTRACT(void*) {
103 NOTHROW;
104 GC_NOTRIGGER;
105 MODE_COOPERATIVE;
106 PRECONDITION(pObj != NULL);
107 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
108 }
109 CONTRACT_END;
110
111 ReflectionPointer * pReflectionPointer = (ReflectionPointer *)OBJECTREFToObject(pObj);
112 void *value = pReflectionPointer->_ptr;
113 RETURN value;
114}
115
116void *InvokeUtil::GetIntPtrValue(OBJECTREF pObj) {
117 CONTRACT(void*) {
118 NOTHROW;
119 GC_NOTRIGGER;
120 MODE_COOPERATIVE;
121 PRECONDITION(pObj != NULL);
122 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
123 }
124 CONTRACT_END;
125
126 RETURN *(void **)((pObj)->UnBox());
127}
128
129void InvokeUtil::CopyArg(TypeHandle th, OBJECTREF *pObjUNSAFE, ArgDestination *argDest) {
130 CONTRACTL {
131 THROWS;
132 GC_NOTRIGGER; // Caller does not protect object references
133 MODE_COOPERATIVE;
134 PRECONDITION(!th.IsNull());
135 PRECONDITION(CheckPointer(pObjUNSAFE));
136 INJECT_FAULT(COMPlusThrowOM());
137 }
138 CONTRACTL_END;
139
140 void *pArgDst = argDest->GetDestinationAddress();
141
142 OBJECTREF rObj = *pObjUNSAFE;
143 MethodTable* pMT;
144 CorElementType oType;
145 CorElementType type;
146
147 if (rObj != 0) {
148 pMT = rObj->GetMethodTable();
149 oType = pMT->GetInternalCorElementType();
150 }
151 else {
152 pMT = 0;
153 oType = ELEMENT_TYPE_OBJECT;
154 }
155 type = th.GetVerifierCorElementType();
156
157 // This basically maps the Signature type our type and calls the CreatePrimitiveValue
158 // method. We can omit this if we get alignment on these types.
159 switch (type) {
160 case ELEMENT_TYPE_BOOLEAN:
161 case ELEMENT_TYPE_I1:
162 case ELEMENT_TYPE_U1:
163 case ELEMENT_TYPE_I2:
164 case ELEMENT_TYPE_U2:
165 case ELEMENT_TYPE_CHAR:
166 case ELEMENT_TYPE_I4:
167 case ELEMENT_TYPE_U4:
168 case ELEMENT_TYPE_R4:
169 IN_WIN32(case ELEMENT_TYPE_I:)
170 IN_WIN32(case ELEMENT_TYPE_U:)
171 {
172 // If we got the univeral zero...Then assign it and exit.
173 if (rObj == 0)
174 *(PVOID *)pArgDst = 0;
175 else
176 {
177 ARG_SLOT slot;
178 CreatePrimitiveValue(type, oType, rObj, &slot);
179 *(PVOID *)pArgDst = (PVOID)slot;
180 }
181 break;
182 }
183
184
185 case ELEMENT_TYPE_I8:
186 case ELEMENT_TYPE_U8:
187 case ELEMENT_TYPE_R8:
188 IN_WIN64(case ELEMENT_TYPE_I:)
189 IN_WIN64(case ELEMENT_TYPE_U:)
190 {
191 // If we got the univeral zero...Then assign it and exit.
192 if (rObj == 0)
193 *(INT64 *)pArgDst = 0;
194 else
195 {
196 ARG_SLOT slot;
197 CreatePrimitiveValue(type, oType, rObj, &slot);
198 *(INT64 *)pArgDst = (INT64)slot;
199 }
200 break;
201 }
202
203 case ELEMENT_TYPE_VALUETYPE:
204 {
205 // If we got the universal zero...Then assign it and exit.
206 if (rObj == 0) {
207 InitValueClassArg(argDest, th.AsMethodTable());
208 }
209 else {
210 if (!th.AsMethodTable()->UnBoxIntoArg(argDest, rObj))
211 COMPlusThrow(kArgumentException, W("Arg_ObjObj"));
212 }
213 break;
214 }
215
216 case ELEMENT_TYPE_SZARRAY: // Single Dim
217 case ELEMENT_TYPE_ARRAY: // General Array
218 case ELEMENT_TYPE_CLASS: // Class
219 case ELEMENT_TYPE_OBJECT:
220 case ELEMENT_TYPE_STRING: // System.String
221 case ELEMENT_TYPE_VAR:
222 {
223 if (rObj == 0)
224 *(PVOID *)pArgDst = 0;
225 else
226 *(PVOID *)pArgDst = OBJECTREFToObject(rObj);
227 break;
228 }
229
230 case ELEMENT_TYPE_BYREF:
231 {
232 //
233 // (obj is the parameter passed to MethodInfo.Invoke, by the caller)
234 // if argument is a primitive
235 // {
236 // if incoming argument, obj, is null
237 // Allocate a boxed object and place ref to it in 'obj'
238 // Unbox 'obj' and pass it to callee
239 // }
240 // if argument is a value class
241 // {
242 // if incoming argument, obj, is null
243 // Allocate an object of that valueclass, and place ref to it in 'obj'
244 // Unbox 'obj' and pass it to callee
245 // }
246 // if argument is an objectref
247 // {
248 // pass obj to callee
249 // }
250 //
251 TypeHandle thBaseType = th.AsTypeDesc()->GetTypeParam();
252
253 // We should never get here for nullable types. Instead invoke
254 // heads these off and morphs the type handle to not be byref anymore
255 _ASSERTE(!Nullable::IsNullableType(thBaseType));
256
257 TypeHandle srcTH = TypeHandle();
258 if (rObj == 0)
259 oType = thBaseType.GetSignatureCorElementType();
260 else
261 srcTH = rObj->GetTypeHandle();
262
263 //CreateByRef only triggers GC in throw path, so it's OK to use the raw unsafe pointer
264 *(PVOID *)pArgDst = CreateByRef(thBaseType, oType, srcTH, rObj, pObjUNSAFE);
265 break;
266 }
267
268 case ELEMENT_TYPE_TYPEDBYREF:
269 {
270 TypedByRef* ptr = (TypedByRef*) pArgDst;
271 TypeHandle srcTH;
272 BOOL bIsZero = FALSE;
273
274 // If we got the univeral zero...Then assign it and exit.
275 if (rObj== 0) {
276 bIsZero = TRUE;
277 ptr->data = 0;
278 ptr->type = TypeHandle();
279 }
280 else {
281 bIsZero = FALSE;
282 srcTH = rObj->GetTypeHandle();
283 ptr->type = rObj->GetTypeHandle();
284 }
285
286 if (!bIsZero)
287 {
288 //CreateByRef only triggers GC in throw path
289 ptr->data = CreateByRef(srcTH, oType, srcTH, rObj, pObjUNSAFE);
290 }
291
292 break;
293 }
294
295 case ELEMENT_TYPE_PTR:
296 case ELEMENT_TYPE_FNPTR:
297 {
298 // If we got the univeral zero...Then assign it and exit.
299 if (rObj == 0) {
300 *(PVOID *)pArgDst = 0;
301 }
302 else {
303 if (rObj->GetMethodTable() == MscorlibBinder::GetClassIfExist(CLASS__POINTER) && type == ELEMENT_TYPE_PTR)
304 *(PVOID *)pArgDst = GetPointerValue(rObj);
305 else if (rObj->GetTypeHandle().AsMethodTable() == MscorlibBinder::GetElementType(ELEMENT_TYPE_I))
306 {
307 ARG_SLOT slot;
308 CreatePrimitiveValue(oType, oType, rObj, &slot);
309 *(PVOID *)pArgDst = (PVOID)slot;
310 }
311 else
312 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
313 }
314 break;
315 }
316
317 case ELEMENT_TYPE_VOID:
318 default:
319 _ASSERTE(!"Unknown Type");
320 COMPlusThrow(kNotSupportedException);
321 }
322}
323
324// CreatePrimitiveValue
325// This routine will validate the object and then place the value into
326// the destination
327// dstType -- The type of the destination
328// srcType -- The type of the source
329// srcObj -- The Object containing the primitive value.
330// pDst -- pointer to the destination
331void InvokeUtil::CreatePrimitiveValue(CorElementType dstType,
332 CorElementType srcType,
333 OBJECTREF srcObj,
334 ARG_SLOT *pDst) {
335 CONTRACTL {
336 THROWS;
337 GC_NOTRIGGER;
338 MODE_COOPERATIVE;
339 PRECONDITION(srcObj != NULL);
340 PRECONDITION(CheckPointer(pDst));
341 INJECT_FAULT(COMPlusThrowOM());
342 }
343 CONTRACTL_END;
344 CreatePrimitiveValue(dstType, srcType, srcObj->UnBox(), srcObj->GetMethodTable(), pDst);
345}
346
347void InvokeUtil::CreatePrimitiveValue(CorElementType dstType,CorElementType srcType,
348 void *pSrc, MethodTable *pSrcMT, ARG_SLOT* pDst)
349{
350
351 CONTRACTL {
352 THROWS;
353 GC_NOTRIGGER;
354 MODE_COOPERATIVE;
355 PRECONDITION(CheckPointer(pDst));
356 INJECT_FAULT(COMPlusThrowOM());
357 }
358 CONTRACTL_END;
359
360 if (!IsPrimitiveType(srcType) || !CanPrimitiveWiden(dstType, srcType))
361 COMPlusThrow(kArgumentException, W("Arg_PrimWiden"));
362
363 ARG_SLOT data = 0;
364
365 switch (srcType) {
366 case ELEMENT_TYPE_I1:
367 data = *(INT8*)pSrc;
368 break;
369 case ELEMENT_TYPE_I2:
370 data = *(INT16*)pSrc;
371 break;
372 IN_WIN32(case ELEMENT_TYPE_I:)
373 case ELEMENT_TYPE_I4:
374 data = *(INT32 *)pSrc;
375 break;
376 IN_WIN64(case ELEMENT_TYPE_I:)
377 case ELEMENT_TYPE_I8:
378 data = *(INT64 *)pSrc;
379 break;
380 default:
381 switch (pSrcMT->GetNumInstanceFieldBytes())
382 {
383 case 1:
384 data = *(UINT8 *)pSrc;
385 break;
386 case 2:
387 data = *(UINT16 *)pSrc;
388 break;
389 case 4:
390 data = *(UINT32 *)pSrc;
391 break;
392 case 8:
393 data = *(UINT64 *)pSrc;
394 break;
395 default:
396 _ASSERTE(!"Unknown conversion");
397 // this is really an impossible condition
398 COMPlusThrow(kNotSupportedException);
399 break;
400 }
401 }
402
403 if (srcType == dstType) {
404 // shortcut
405 *pDst = data;
406 return;
407 }
408
409 // Copy the data and return
410 switch (dstType) {
411 case ELEMENT_TYPE_BOOLEAN:
412 case ELEMENT_TYPE_I1:
413 case ELEMENT_TYPE_U1:
414 case ELEMENT_TYPE_CHAR:
415 case ELEMENT_TYPE_I2:
416 case ELEMENT_TYPE_U2:
417 case ELEMENT_TYPE_I4:
418 case ELEMENT_TYPE_U4:
419 case ELEMENT_TYPE_I:
420 case ELEMENT_TYPE_U:
421 case ELEMENT_TYPE_I8:
422 case ELEMENT_TYPE_U8:
423 switch (srcType) {
424 case ELEMENT_TYPE_BOOLEAN:
425 case ELEMENT_TYPE_I1:
426 case ELEMENT_TYPE_U1:
427 case ELEMENT_TYPE_CHAR:
428 case ELEMENT_TYPE_I2:
429 case ELEMENT_TYPE_U2:
430 case ELEMENT_TYPE_I4:
431 case ELEMENT_TYPE_U4:
432 case ELEMENT_TYPE_I:
433 case ELEMENT_TYPE_U:
434 case ELEMENT_TYPE_I8:
435 case ELEMENT_TYPE_U8:
436 *pDst = data;
437 break;
438 case ELEMENT_TYPE_R4:
439 *pDst = (I8)(*(R4*)pSrc);
440 break;
441 case ELEMENT_TYPE_R8:
442 *pDst = (I8)(*(R8*)pSrc);
443 break;
444 default:
445 _ASSERTE(!"Unknown conversion");
446 // this is really an impossible condition
447 COMPlusThrow(kNotSupportedException);
448 }
449 break;
450 case ELEMENT_TYPE_R4:
451 case ELEMENT_TYPE_R8:
452 {
453 R8 r8 = 0;
454 switch (srcType) {
455 case ELEMENT_TYPE_BOOLEAN:
456 case ELEMENT_TYPE_I1:
457 case ELEMENT_TYPE_I2:
458 case ELEMENT_TYPE_I4:
459 IN_WIN32(case ELEMENT_TYPE_I:)
460 r8 = (R8)((INT32)data);
461 break;
462 case ELEMENT_TYPE_U1:
463 case ELEMENT_TYPE_CHAR:
464 case ELEMENT_TYPE_U2:
465 case ELEMENT_TYPE_U4:
466 IN_WIN32(case ELEMENT_TYPE_U:)
467 r8 = (R8)((UINT32)data);
468 break;
469 case ELEMENT_TYPE_U8:
470 IN_WIN64(case ELEMENT_TYPE_U:)
471 r8 = (R8)((UINT64)data);
472 break;
473 case ELEMENT_TYPE_I8:
474 IN_WIN64(case ELEMENT_TYPE_I:)
475 r8 = (R8)((INT64)data);
476 break;
477 case ELEMENT_TYPE_R4:
478 r8 = *(R4*)pSrc;
479 break;
480 case ELEMENT_TYPE_R8:
481 r8 = *(R8*)pSrc;
482 break;
483 default:
484 _ASSERTE(!"Unknown R4 or R8 conversion");
485 // this is really an impossible condition
486 COMPlusThrow(kNotSupportedException);
487 }
488
489 if (dstType == ELEMENT_TYPE_R4) {
490 R4 r4 = (R4)r8;
491 *pDst = (UINT32&)r4;
492 }
493 else {
494 *pDst = (UINT64&)r8;
495 }
496
497 }
498 break;
499 default:
500 _ASSERTE(!"Unknown conversion");
501 }
502}
503
504void* InvokeUtil::CreateByRef(TypeHandle dstTh,
505 CorElementType srcType,
506 TypeHandle srcTH,
507 OBJECTREF srcObj,
508 OBJECTREF *pIncomingObj) {
509 CONTRACTL {
510 THROWS;
511 GC_NOTRIGGER;
512 MODE_COOPERATIVE;
513 PRECONDITION(!dstTh.IsNull());
514 PRECONDITION(CheckPointer(pIncomingObj));
515
516 INJECT_FAULT(COMPlusThrowOM());
517 }
518 CONTRACTL_END;
519
520 CorElementType dstType = dstTh.GetSignatureCorElementType();
521 if (IsPrimitiveType(srcType) && IsPrimitiveType(dstType)) {
522 if (dstType != srcType)
523 {
524 CONTRACT_VIOLATION (GCViolation);
525 COMPlusThrow(kArgumentException,W("Arg_PrimWiden"));
526 }
527
528 return srcObj->UnBox();
529 }
530
531 if (srcTH.IsNull()) {
532 return pIncomingObj;
533 }
534
535 _ASSERTE(srcObj != NULL);
536
537 if (dstType == ELEMENT_TYPE_VALUETYPE) {
538 return srcObj->UnBox();
539 }
540 else
541 return pIncomingObj;
542}
543
544// GetBoxedObject
545// Given an address of a primitve type, this will box that data...
546// <TODO>@TODO: We need to handle all value classes?</TODO>
547OBJECTREF InvokeUtil::GetBoxedObject(TypeHandle th, void* pData) {
548 CONTRACTL {
549 THROWS;
550 GC_TRIGGERS;
551 MODE_COOPERATIVE;
552 PRECONDITION(!th.IsNull());
553 PRECONDITION(CheckPointer(pData));
554
555 INJECT_FAULT(COMPlusThrowOM());
556 }
557 CONTRACTL_END;
558
559 MethodTable *pMethTable = th.GetMethodTable();
560 PREFIX_ASSUME(pMethTable != NULL);
561 // Save off the data. We are going to create and object
562 // which may cause GC to occur.
563 int size = pMethTable->GetNumInstanceFieldBytes();
564 void *p = _alloca(size);
565 memcpy(p, pData, size);
566 OBJECTREF retO = pMethTable->Box(p);
567 return retO;
568}
569
570//ValidField
571// This method checks that the object can be widened to the proper type
572void InvokeUtil::ValidField(TypeHandle th, OBJECTREF* value)
573{
574 CONTRACTL {
575 THROWS;
576 GC_TRIGGERS;
577 MODE_COOPERATIVE;
578 PRECONDITION(!th.IsNull());
579 PRECONDITION(CheckPointer(value));
580 PRECONDITION(IsProtectedByGCFrame (value));
581 INJECT_FAULT(COMPlusThrowOM());
582 }
583 CONTRACTL_END;
584
585 if ((*value) == 0)
586 return;
587
588 MethodTable* pMT;
589 CorElementType oType;
590 CorElementType type = th.GetSignatureCorElementType();
591 pMT = (*value)->GetMethodTable();
592 oType = TypeHandle(pMT).GetSignatureCorElementType();
593
594 // handle pointers
595 if (type == ELEMENT_TYPE_PTR || type == ELEMENT_TYPE_FNPTR) {
596 if (MscorlibBinder::IsClass((*value)->GetMethodTable(), CLASS__POINTER) && type == ELEMENT_TYPE_PTR) {
597 TypeHandle srcTH = GetPointerType(*value);
598
599 if (!IsVoidPtr(th)) {
600 if (!srcTH.CanCastTo(th))
601 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
602 }
603 return;
604 }
605 else if (MscorlibBinder::IsClass((*value)->GetMethodTable(), CLASS__INTPTR)) {
606 return;
607 }
608
609 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
610 }
611
612 // Need to handle Object special
613 if (type == ELEMENT_TYPE_CLASS || type == ELEMENT_TYPE_VALUETYPE ||
614 type == ELEMENT_TYPE_OBJECT || type == ELEMENT_TYPE_STRING ||
615 type == ELEMENT_TYPE_ARRAY || type == ELEMENT_TYPE_SZARRAY)
616 {
617
618 if (th.GetMethodTable() == g_pObjectClass)
619 return;
620 if (IsPrimitiveType(oType)) {
621 if (type != ELEMENT_TYPE_VALUETYPE)
622 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
623
624 // Legacy behavior: The following if disallows assigning primitives to enums.
625 if (th.IsEnum())
626 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
627
628 type = th.GetVerifierCorElementType();
629 if (IsPrimitiveType(type))
630 {
631 if (CanPrimitiveWiden(type, oType))
632 return;
633 else
634 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
635 }
636 }
637
638 if (!ObjIsInstanceOf(OBJECTREFToObject(*value), th)) {
639 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
640 }
641 return;
642 }
643
644
645 if (!IsPrimitiveType(oType))
646 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
647 // Now make sure we can widen into the proper type -- CanWiden may run GC...
648 if (!CanPrimitiveWiden(type,oType))
649 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
650}
651
652//
653// CreateObjectAfterInvoke
654// This routine will create the specified object from the value returned by the Invoke target.
655//
656// This does not handle the ELEMENT_TYPE_VALUETYPE case. The caller must preallocate the box object and
657// copy the value type into it afterward.
658//
659OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) {
660 CONTRACTL {
661 THROWS;
662 GC_TRIGGERS;
663 MODE_COOPERATIVE;
664 PRECONDITION(!th.IsNull());
665
666 INJECT_FAULT(COMPlusThrowOM());
667 }
668 CONTRACTL_END;
669
670 CorElementType type = th.GetSignatureCorElementType();
671 OBJECTREF obj = NULL;
672
673 // WARNING: pValue can be an inner reference into a managed object and it is not protected from GC. You must do nothing that
674 // triggers a GC until the all the data it points to has been captured in a GC-protected location.
675
676 // Handle the non-table types
677 switch (type) {
678 case ELEMENT_TYPE_VOID:
679 break;
680
681 case ELEMENT_TYPE_PTR:
682 {
683 obj = CreatePointer(th, *(void **)pValue);
684 break;
685 }
686
687 case ELEMENT_TYPE_CLASS: // Class
688 case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero
689 case ELEMENT_TYPE_ARRAY: // General Array
690 case ELEMENT_TYPE_STRING:
691 case ELEMENT_TYPE_OBJECT:
692 case ELEMENT_TYPE_VAR:
693 obj = *(OBJECTREF *)pValue;
694 break;
695
696 case ELEMENT_TYPE_FNPTR:
697 {
698 LPVOID capturedValue = *(LPVOID*)pValue;
699 INDEBUG(pValue = (LPVOID)0xcccccccc); // We're about to allocate a GC object - can no longer trust pValue
700 obj = AllocateObject(MscorlibBinder::GetElementType(ELEMENT_TYPE_I));
701 *(LPVOID*)(obj->UnBox()) = capturedValue;
702 }
703 break;
704
705 default:
706 _ASSERTE(!"Unknown Type");
707 COMPlusThrow(kNotSupportedException);
708 }
709
710 return obj;
711}
712
713// This is a special purpose Exception creation function. It
714// creates the ReflectionTypeLoadException placing the passed
715// classes array and exception array into it.
716OBJECTREF InvokeUtil::CreateClassLoadExcept(OBJECTREF* classes, OBJECTREF* except) {
717 CONTRACT(OBJECTREF) {
718 THROWS;
719 GC_TRIGGERS;
720 MODE_COOPERATIVE;
721 PRECONDITION(CheckPointer(classes));
722 PRECONDITION(CheckPointer(except));
723 PRECONDITION(IsProtectedByGCFrame (classes));
724 PRECONDITION(IsProtectedByGCFrame (except));
725
726 POSTCONDITION(RETVAL != NULL);
727
728 INJECT_FAULT(COMPlusThrowOM());
729 }
730 CONTRACT_END;
731
732 OBJECTREF oRet = 0;
733
734 struct {
735 OBJECTREF o;
736 STRINGREF str;
737 } gc;
738 ZeroMemory(&gc, sizeof(gc));
739
740 MethodTable *pVMClassLoadExcept = MscorlibBinder::GetException(kReflectionTypeLoadException);
741 gc.o = AllocateObject(pVMClassLoadExcept);
742 GCPROTECT_BEGIN(gc);
743 ARG_SLOT args[4];
744
745 // Retrieve the resource string.
746 ResMgrGetString(W("ReflectionTypeLoad_LoadFailed"), &gc.str);
747
748 MethodDesc* pMD = MemberLoader::FindMethod(gc.o->GetMethodTable(),
749 COR_CTOR_METHOD_NAME, &gsig_IM_ArrType_ArrException_Str_RetVoid);
750
751 if (!pMD)
752 {
753 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
754 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
755 }
756
757 MethodDescCallSite ctor(pMD);
758
759 // Call the constructor
760 args[0] = ObjToArgSlot(gc.o);
761 args[1] = ObjToArgSlot(*classes);
762 args[2] = ObjToArgSlot(*except);
763 args[3] = ObjToArgSlot((OBJECTREF)gc.str);
764
765 ctor.Call(args);
766
767 oRet = gc.o;
768
769 GCPROTECT_END();
770 RETURN oRet;
771}
772
773OBJECTREF InvokeUtil::CreateTargetExcept(OBJECTREF* except) {
774 CONTRACT(OBJECTREF) {
775 THROWS;
776 GC_TRIGGERS;
777 MODE_COOPERATIVE;
778 PRECONDITION(CheckPointer(except));
779 PRECONDITION(IsProtectedByGCFrame (except));
780
781 POSTCONDITION(RETVAL != NULL);
782
783 INJECT_FAULT(COMPlusThrowOM());
784 }
785 CONTRACT_END;
786
787 OBJECTREF o;
788 OBJECTREF oRet = 0;
789
790 MethodTable *pVMTargetExcept = MscorlibBinder::GetException(kTargetInvocationException);
791 o = AllocateObject(pVMTargetExcept);
792 GCPROTECT_BEGIN(o);
793 ARG_SLOT args[2];
794
795 MethodDesc* pMD = MemberLoader::FindMethod(o->GetMethodTable(),
796 COR_CTOR_METHOD_NAME, &gsig_IM_Exception_RetVoid);
797
798 if (!pMD)
799 {
800 MAKE_WIDEPTR_FROMUTF8(wzMethodName, COR_CTOR_METHOD_NAME);
801 COMPlusThrowNonLocalized(kMissingMethodException, wzMethodName);
802 }
803
804 MethodDescCallSite ctor(pMD);
805
806 // Call the constructor
807 args[0] = ObjToArgSlot(o);
808 // for security, don't allow a non-exception object to be spoofed as an exception object. We cast later and
809 // don't check and this could cause us grief.
810 _ASSERTE(!except || IsException((*except)->GetMethodTable())); // how do we get non-exceptions?
811 if (except && IsException((*except)->GetMethodTable()))
812 {
813 args[1] = ObjToArgSlot(*except);
814 }
815 else
816 {
817 args[1] = NULL;
818 }
819
820 ctor.Call(args);
821
822 oRet = o;
823
824 GCPROTECT_END();
825 RETURN oRet;
826}
827
828// ChangeType
829// This method will invoke the Binder change type method on the object
830// binder -- The Binder object
831// srcObj -- The source object to be changed
832// th -- The TypeHandel of the target type
833// locale -- The locale passed to the class.
834OBJECTREF InvokeUtil::ChangeType(OBJECTREF binder, OBJECTREF srcObj, TypeHandle th, OBJECTREF locale) {
835 CONTRACTL {
836 THROWS;
837 GC_TRIGGERS;
838 MODE_COOPERATIVE;
839 PRECONDITION(binder != NULL);
840 PRECONDITION(srcObj != NULL);
841
842 INJECT_FAULT(COMPlusThrowOM());
843 }
844 CONTRACTL_END;
845
846 OBJECTREF typeClass = NULL;
847 OBJECTREF o;
848
849 struct _gc {
850 OBJECTREF binder;
851 OBJECTREF srcObj;
852 OBJECTREF locale;
853 OBJECTREF typeClass;
854 } gc;
855
856 gc.binder = binder;
857 gc.srcObj = srcObj;
858 gc.locale = locale;
859 gc.typeClass = NULL;
860
861 GCPROTECT_BEGIN(gc);
862
863 MethodDescCallSite changeType(METHOD__BINDER__CHANGE_TYPE, &gc.binder);
864
865 // Now call this method on this object.
866 typeClass = th.GetManagedClassObject();
867
868 ARG_SLOT pNewArgs[] = {
869 ObjToArgSlot(gc.binder),
870 ObjToArgSlot(gc.srcObj),
871 ObjToArgSlot(gc.typeClass),
872 ObjToArgSlot(gc.locale),
873 };
874
875 o = changeType.Call_RetOBJECTREF(pNewArgs);
876
877 GCPROTECT_END();
878
879 return o;
880}
881
882// Ensure that the field is declared on the type or subtype of the type to which the typed reference refers.
883// Note that a typed reference is a reference to an object and is not a field on that object (as in C# ref).
884// Ensure that if the field is an instance field that the typed reference is not null.
885void InvokeUtil::ValidateObjectTarget(FieldDesc *pField, TypeHandle enclosingType, OBJECTREF *target) {
886 CONTRACTL {
887 THROWS;
888 GC_TRIGGERS;
889 MODE_COOPERATIVE;
890 PRECONDITION(CheckPointer(pField));
891 PRECONDITION(!enclosingType.IsNull() || pField->IsStatic());
892 PRECONDITION(CheckPointer(target));
893
894 INJECT_FAULT(COMPlusThrowOM());
895 }
896 CONTRACTL_END;
897
898 if (pField->IsStatic() && (enclosingType.IsNull() || !*target))
899 return;
900
901 if (!pField->IsStatic() && !*target)
902 COMPlusThrow(kTargetException,W("RFLCT.Targ_StatFldReqTarg"));
903
904 // Verify that the object is of the proper type...
905 TypeHandle ty = (*target)->GetTrueTypeHandle();
906 while (!ty.IsNull() && ty != enclosingType)
907 ty = ty.GetParent();
908
909 // Give a second chance to thunking classes to do the
910 // correct cast
911 if (ty.IsNull()) {
912 {
913 COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
914 }
915 }
916}
917
918// SetValidField
919// Given an target object, a value object and a field this method will set the field
920// on the target object. The field must be validate before calling this.
921void InvokeUtil::SetValidField(CorElementType fldType,
922 TypeHandle fldTH,
923 FieldDesc *pField,
924 OBJECTREF *target,
925 OBJECTREF *valueObj,
926 TypeHandle declaringType,
927 CLR_BOOL *pDomainInitialized) {
928 CONTRACTL {
929 THROWS;
930 GC_TRIGGERS;
931 MODE_COOPERATIVE;
932 PRECONDITION(!fldTH.IsNull());
933 PRECONDITION(CheckPointer(pField));
934 PRECONDITION(CheckPointer(target));
935 PRECONDITION(CheckPointer(valueObj));
936 PRECONDITION(IsProtectedByGCFrame (target));
937 PRECONDITION(IsProtectedByGCFrame (valueObj));
938 PRECONDITION(declaringType.IsNull () || !declaringType.IsTypeDesc());
939
940 INJECT_FAULT(COMPlusThrowOM());
941 }
942 CONTRACTL_END;
943
944 // We don't allow setting the field of nullable<T> (hasValue and value)
945 // Because you can't independantly set them for this type.
946 if (!declaringType.IsNull() && Nullable::IsNullableType(declaringType.GetMethodTable()))
947 COMPlusThrow(kNotSupportedException);
948
949 // call the <cinit>
950 OBJECTREF Throwable = NULL;
951
952 MethodTable * pDeclMT = NULL;
953 if (!declaringType.IsNull())
954 {
955 pDeclMT = declaringType.GetMethodTable();
956
957 if (pDeclMT->IsSharedByGenericInstantiations())
958 COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
959 }
960
961 if (*pDomainInitialized == FALSE)
962 {
963 EX_TRY
964 {
965 if (declaringType.IsNull())
966 {
967 pField->GetModule()->GetGlobalMethodTable()->EnsureInstanceActive();
968 pField->GetModule()->GetGlobalMethodTable()->CheckRunClassInitThrowing();
969 }
970 else
971 {
972 pDeclMT->EnsureInstanceActive();
973 pDeclMT->CheckRunClassInitThrowing();
974
975 *pDomainInitialized = TRUE;
976 }
977 }
978 EX_CATCH_THROWABLE(&Throwable);
979 }
980#ifdef _DEBUG
981 else if (*pDomainInitialized == TRUE && !declaringType.IsNull())
982 CONSISTENCY_CHECK(declaringType.GetMethodTable()->CheckActivated());
983#endif
984
985 if(Throwable != NULL)
986 {
987 GCPROTECT_BEGIN(Throwable);
988 OBJECTREF except = CreateTargetExcept(&Throwable);
989 COMPlusThrow(except);
990 GCPROTECT_END();
991 }
992
993 // Set the field
994 ARG_SLOT value;
995
996 void* valueptr;
997 switch (fldType) {
998 case ELEMENT_TYPE_VOID:
999 _ASSERTE(!"Void used as Field Type!");
1000 COMPlusThrow(kNotSupportedException);
1001
1002 case ELEMENT_TYPE_BOOLEAN: // boolean
1003 case ELEMENT_TYPE_I1: // byte
1004 case ELEMENT_TYPE_U1: // unsigned byte
1005 value = 0;
1006 if (*valueObj != 0) {
1007 MethodTable *p = (*valueObj)->GetMethodTable();
1008 CorElementType oType = p->GetInternalCorElementType();
1009 CreatePrimitiveValue(fldType, oType, *valueObj, &value);
1010 }
1011
1012 if (pField->IsStatic())
1013 pField->SetStaticValue8((unsigned char)value);
1014 else
1015 pField->SetValue8(*target,(unsigned char)value);
1016 break;
1017
1018 case ELEMENT_TYPE_I2: // short
1019 case ELEMENT_TYPE_U2: // unsigned short
1020 case ELEMENT_TYPE_CHAR: // char
1021 value = 0;
1022 if (*valueObj != 0) {
1023 MethodTable *p = (*valueObj)->GetMethodTable();
1024 CorElementType oType = p->GetInternalCorElementType();
1025 CreatePrimitiveValue(fldType, oType, *valueObj, &value);
1026 }
1027
1028 if (pField->IsStatic())
1029 pField->SetStaticValue16((short)value);
1030 else
1031 pField->SetValue16(*target, (short)value);
1032 break;
1033
1034 case ELEMENT_TYPE_I:
1035 valueptr = *valueObj != 0 ? GetIntPtrValue(*valueObj) : NULL;
1036 if (pField->IsStatic())
1037 pField->SetStaticValuePtr(valueptr);
1038 else
1039 pField->SetValuePtr(*target,valueptr);
1040 break;
1041
1042 case ELEMENT_TYPE_U:
1043 valueptr = *valueObj != 0 ? GetIntPtrValue(*valueObj) : NULL;
1044 if (pField->IsStatic())
1045 pField->SetStaticValuePtr(valueptr);
1046 else
1047 pField->SetValuePtr(*target,valueptr);
1048 break;
1049
1050 case ELEMENT_TYPE_PTR: // pointers
1051 if (*valueObj != 0 && MscorlibBinder::IsClass((*valueObj)->GetMethodTable(), CLASS__POINTER)) {
1052 valueptr = GetPointerValue(*valueObj);
1053 if (pField->IsStatic())
1054 pField->SetStaticValuePtr(valueptr);
1055 else
1056 pField->SetValuePtr(*target,valueptr);
1057 break;
1058 }
1059 // drop through
1060 case ELEMENT_TYPE_FNPTR:
1061 valueptr = *valueObj != 0 ? GetIntPtrValue(*valueObj) : NULL;
1062 if (pField->IsStatic())
1063 pField->SetStaticValuePtr(valueptr);
1064 else
1065 pField->SetValuePtr(*target,valueptr);
1066 break;
1067
1068 case ELEMENT_TYPE_I4: // int
1069 case ELEMENT_TYPE_U4: // unsigned int
1070 case ELEMENT_TYPE_R4: // float
1071 value = 0;
1072 if (*valueObj != 0) {
1073 MethodTable *p = (*valueObj)->GetMethodTable();
1074 CorElementType oType = p->GetInternalCorElementType();
1075 CreatePrimitiveValue(fldType, oType, *valueObj, &value);
1076 }
1077
1078 if (pField->IsStatic())
1079 pField->SetStaticValue32((int)value);
1080 else
1081 pField->SetValue32(*target, (int)value);
1082 break;
1083
1084 case ELEMENT_TYPE_I8: // long
1085 case ELEMENT_TYPE_U8: // unsigned long
1086 case ELEMENT_TYPE_R8: // double
1087 value = 0;
1088 if (*valueObj != 0) {
1089 MethodTable *p = (*valueObj)->GetMethodTable();
1090 CorElementType oType = p->GetInternalCorElementType();
1091 CreatePrimitiveValue(fldType, oType, *valueObj, &value);
1092 }
1093
1094 if (pField->IsStatic())
1095 pField->SetStaticValue64(value);
1096 else
1097 pField->SetValue64(*target,value);
1098 break;
1099
1100 case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero
1101 case ELEMENT_TYPE_ARRAY: // General Array
1102 case ELEMENT_TYPE_CLASS:
1103 case ELEMENT_TYPE_OBJECT:
1104 case ELEMENT_TYPE_VAR:
1105 if (pField->IsStatic())
1106 pField->SetStaticOBJECTREF(*valueObj);
1107 else
1108 pField->SetRefValue(*target, *valueObj);
1109 break;
1110
1111 case ELEMENT_TYPE_VALUETYPE:
1112 {
1113 _ASSERTE(!fldTH.IsTypeDesc());
1114 MethodTable *pMT = fldTH.AsMethodTable();
1115 {
1116 void* pFieldData;
1117 if (pField->IsStatic())
1118 pFieldData = pField->GetCurrentStaticAddress();
1119 else
1120 pFieldData = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object);
1121
1122 if (*valueObj == NULL)
1123 InitValueClass(pFieldData, pMT);
1124 else
1125 pMT->UnBoxIntoUnchecked(pFieldData, *valueObj);
1126 }
1127 }
1128 break;
1129
1130 default:
1131 _ASSERTE(!"Unknown Type");
1132 // this is really an impossible condition
1133 COMPlusThrow(kNotSupportedException);
1134 }
1135}
1136
1137// GetFieldValue
1138// This method will return an ARG_SLOT containing the value of the field.
1139// GetFieldValue
1140// This method will return an ARG_SLOT containing the value of the field.
1141OBJECTREF InvokeUtil::GetFieldValue(FieldDesc* pField, TypeHandle fieldType, OBJECTREF* target, TypeHandle declaringType, CLR_BOOL *pDomainInitialized) {
1142 CONTRACTL {
1143 THROWS;
1144 GC_TRIGGERS;
1145 MODE_COOPERATIVE;
1146 PRECONDITION(CheckPointer(pField));
1147 PRECONDITION(!fieldType.IsNull());
1148 PRECONDITION(CheckPointer(target));
1149 PRECONDITION(declaringType.IsNull () || !declaringType.IsTypeDesc());
1150
1151 INJECT_FAULT(COMPlusThrowOM());
1152 }
1153 CONTRACTL_END;
1154
1155 OBJECTREF obj = NULL;
1156
1157 // call the .cctor
1158 OBJECTREF Throwable = NULL;
1159
1160 MethodTable * pDeclMT = NULL;
1161 if (!declaringType.IsNull())
1162 {
1163 pDeclMT = declaringType.GetMethodTable();
1164
1165 if (pDeclMT->IsSharedByGenericInstantiations())
1166 COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
1167 }
1168
1169 if (*pDomainInitialized == FALSE)
1170 {
1171 EX_TRY
1172 {
1173 if (declaringType.IsNull())
1174 {
1175 pField->GetModule()->GetGlobalMethodTable()->EnsureInstanceActive();
1176 pField->GetModule()->GetGlobalMethodTable()->CheckRunClassInitThrowing();
1177 }
1178 else
1179 {
1180 pDeclMT->EnsureInstanceActive();
1181 pDeclMT->CheckRunClassInitThrowing();
1182
1183 *pDomainInitialized = TRUE;
1184 }
1185 }
1186 EX_CATCH_THROWABLE(&Throwable);
1187 }
1188#ifdef _DEBUG
1189 else if (*pDomainInitialized == TRUE && !declaringType.IsNull())
1190 CONSISTENCY_CHECK(declaringType.GetMethodTable()->CheckActivated());
1191#endif
1192
1193
1194 if(Throwable != NULL)
1195 {
1196 GCPROTECT_BEGIN(Throwable);
1197 OBJECTREF except = CreateTargetExcept(&Throwable);
1198 COMPlusThrow(except);
1199 GCPROTECT_END();
1200 }
1201
1202 // We don't allow getting the field just so we don't have more specical
1203 // cases than we need to. The we need at least the throw check to insure
1204 // we don't allow data corruption, but
1205 if (!declaringType.IsNull() && Nullable::IsNullableType(pDeclMT))
1206 COMPlusThrow(kNotSupportedException);
1207
1208 CorElementType fieldElementType = pField->GetFieldType();
1209
1210 switch (fieldElementType) {
1211
1212 case ELEMENT_TYPE_BOOLEAN: // boolean
1213 case ELEMENT_TYPE_I1: // byte
1214 case ELEMENT_TYPE_U1: // unsigned byte
1215 case ELEMENT_TYPE_I2: // short
1216 case ELEMENT_TYPE_U2: // unsigned short
1217 case ELEMENT_TYPE_CHAR: // char
1218 case ELEMENT_TYPE_I4: // int
1219 case ELEMENT_TYPE_U4: // unsigned int
1220 case ELEMENT_TYPE_R4: // float
1221 case ELEMENT_TYPE_I8: // long
1222 case ELEMENT_TYPE_U8: // unsigned long
1223 case ELEMENT_TYPE_R8: // double
1224 case ELEMENT_TYPE_I:
1225 case ELEMENT_TYPE_U:
1226 {
1227 // create the object and copy
1228 fieldType.AsMethodTable()->EnsureActive();
1229 obj = AllocateObject(fieldType.AsMethodTable());
1230 GCPROTECT_BEGIN(obj);
1231 if (pField->IsStatic())
1232 CopyValueClass(obj->UnBox(),
1233 pField->GetCurrentStaticAddress(),
1234 fieldType.AsMethodTable(),
1235 obj->GetAppDomain());
1236 else
1237 pField->GetInstanceField(*target, obj->UnBox());
1238 GCPROTECT_END();
1239 break;
1240 }
1241
1242 case ELEMENT_TYPE_OBJECT:
1243 case ELEMENT_TYPE_CLASS:
1244 case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero
1245 case ELEMENT_TYPE_ARRAY: // general array
1246 case ELEMENT_TYPE_VAR:
1247 if (pField->IsStatic())
1248 obj = pField->GetStaticOBJECTREF();
1249 else
1250 obj = pField->GetRefValue(*target);
1251 break;
1252
1253 case ELEMENT_TYPE_VALUETYPE:
1254 {
1255 // Value classes require createing a boxed version of the field and then
1256 // copying from the source...
1257 // Allocate an object to return...
1258 _ASSERTE(!fieldType.IsTypeDesc());
1259
1260 void *p = NULL;
1261 fieldType.AsMethodTable()->EnsureActive();
1262 obj = fieldType.AsMethodTable()->Allocate();
1263 GCPROTECT_BEGIN(obj);
1264 // calculate the offset to the field...
1265 if (pField->IsStatic())
1266 p = pField->GetCurrentStaticAddress();
1267 else {
1268 p = (*((BYTE**)target)) + pField->GetOffset() + sizeof(Object);
1269 }
1270 GCPROTECT_END();
1271
1272 // copy the field to the unboxed object.
1273 // note: this will be done only for the non-remoting case
1274 if (p) {
1275 CopyValueClass(obj->GetData(), p, fieldType.AsMethodTable(), obj->GetAppDomain());
1276 }
1277
1278 // If it is a Nullable<T>, box it using Nullable<T> conventions.
1279 // TODO: this double allocates on constructions which is wastefull
1280 obj = Nullable::NormalizeBox(obj);
1281 break;
1282 }
1283
1284 case ELEMENT_TYPE_FNPTR:
1285 {
1286 void *value = NULL;
1287 if (pField->IsStatic())
1288 value = pField->GetStaticValuePtr();
1289 else
1290 value = pField->GetValuePtr(*target);
1291
1292 MethodTable *pIntPtrMT = MscorlibBinder::GetClass(CLASS__INTPTR);
1293 obj = AllocateObject(pIntPtrMT);
1294 CopyValueClass(obj->UnBox(), &value, pIntPtrMT, obj->GetAppDomain());
1295 break;
1296 }
1297
1298 case ELEMENT_TYPE_PTR:
1299 {
1300 void *value = NULL;
1301 if (pField->IsStatic())
1302 value = pField->GetStaticValuePtr();
1303 else
1304 value = pField->GetValuePtr(*target);
1305 obj = CreatePointer(fieldType, value);
1306 break;
1307 }
1308
1309 default:
1310 _ASSERTE(!"Unknown Type");
1311 // this is really an impossible condition
1312 COMPlusThrow(kNotSupportedException);
1313 }
1314
1315 return obj;
1316}
1317
1318void RefSecContext::FindCaller()
1319{
1320 CONTRACTL {
1321 THROWS;
1322 GC_TRIGGERS;
1323 MODE_ANY;
1324 }
1325 CONTRACTL_END;
1326
1327 if (!m_fCheckedCaller)
1328 {
1329 m_pCaller = SystemDomain::GetCallersMethod(NULL, &m_pCallerDomain);
1330
1331 // If we didn't find a caller, we were called through interop. In this
1332 // case we know we're going to get full permissions.
1333 if (m_pCaller == NULL && !m_fCheckedPerm) {
1334 m_fCallerHasPerm = true;
1335
1336 m_fCheckedPerm = true;
1337 }
1338 m_fCheckedCaller = true;
1339 }
1340}
1341
1342MethodDesc *RefSecContext::GetCallerMethod() {
1343 CONTRACTL {
1344 THROWS;
1345 GC_TRIGGERS;
1346 MODE_ANY;
1347 }
1348 CONTRACTL_END;
1349
1350 FindCaller();
1351 return m_pCaller;
1352}
1353
1354AppDomain *RefSecContext::GetCallerDomain() {
1355 CONTRACTL {
1356 THROWS;
1357 GC_TRIGGERS;
1358 MODE_ANY;
1359 }
1360 CONTRACTL_END;
1361
1362 FindCaller();
1363 return m_pCallerDomain;
1364}
1365
1366MethodTable *RefSecContext::GetCallerMT() {
1367 CONTRACTL {
1368 THROWS;
1369 GC_TRIGGERS;
1370 MODE_ANY;
1371 }
1372 CONTRACTL_END;
1373
1374 MethodDesc *pCaller = GetCallerMethod();
1375 return pCaller ? pCaller->GetMethodTable() : NULL;
1376}
1377
1378Assembly *RefSecContext::GetCallerAssembly() {
1379 CONTRACTL {
1380 THROWS;
1381 GC_TRIGGERS;
1382 MODE_ANY;
1383 }
1384 CONTRACTL_END;
1385
1386 MethodTable *pMT = GetCallerMT();
1387 return pMT ? pMT->GetAssembly() : NULL;
1388}
1389
1390bool RefSecContext::IsCalledFromInterop()
1391{
1392 CONTRACTL {
1393 THROWS;
1394 GC_TRIGGERS;
1395 MODE_ANY;
1396 }
1397 CONTRACTL_END;
1398
1399 MethodDesc *pCaller = GetCallerMethod();
1400 return (pCaller == NULL);
1401}
1402
1403void InvokeUtil::CanAccessClass(RefSecContext* pCtx,
1404 MethodTable* pClass,
1405 BOOL checkAccessForImplicitValueTypeCtor /*= FALSE*/)
1406{
1407 CONTRACTL
1408 {
1409 THROWS;
1410 GC_TRIGGERS;
1411 MODE_COOPERATIVE;
1412 }
1413 CONTRACTL_END;
1414
1415 InvokeUtil::CheckAccessClass(pCtx, pClass, checkAccessForImplicitValueTypeCtor);
1416
1417}
1418
1419#ifndef DACCESS_COMPILE
1420void InvokeUtil::CanAccessMethod(MethodDesc* pMeth,
1421 MethodTable* pParentMT,
1422 MethodTable* pInstanceMT,
1423 RefSecContext* pSCtx,
1424 BOOL fCriticalToFullDemand,
1425 BOOL checkSkipVer /*= FALSE*/)
1426{
1427 CONTRACTL
1428 {
1429 THROWS;
1430 GC_TRIGGERS;
1431 MODE_COOPERATIVE;
1432 PRECONDITION(CheckPointer(pMeth));
1433 PRECONDITION(CheckPointer(pSCtx));
1434 }
1435 CONTRACTL_END;
1436
1437 InvokeUtil::CheckAccessMethod(pSCtx,
1438 pParentMT,
1439 pInstanceMT,
1440 pMeth);
1441}
1442#endif // #ifndef DACCESS_COMPILE
1443
1444void InvokeUtil::CanAccessField(RefSecContext* pCtx,
1445 MethodTable* pTargetMT,
1446 MethodTable* pInstanceMT,
1447 FieldDesc* pTargetField)
1448{
1449 CONTRACTL
1450 {
1451 THROWS;
1452 GC_TRIGGERS;
1453 MODE_COOPERATIVE;
1454 }
1455 CONTRACTL_END;
1456
1457 InvokeUtil::CheckAccessField(pCtx, pTargetMT, pInstanceMT, pTargetField);
1458
1459}
1460
1461//
1462// Ensure that a type is accessible, throwing a TypeLoadException if not
1463//
1464// Arguments:
1465// pCtx - current reflection context
1466// pTargetMT - class to check access to
1467// checkAccessForImplicitValueTypeCtor - ValueTypes always have an implicit constructor.
1468// If a user tries to do "new ValueType()", we support it even if there is not
1469// explicit constructor. However, we want to throw MethodAccessException in this case,
1470// though the accessibility check is done against the type.
1471//
1472// Return Value:
1473// Nothing - throws an exception if access is not allowed
1474//
1475
1476// static
1477void InvokeUtil::CheckAccessClass(RefSecContext *pCtx,
1478 MethodTable *pClassMT,
1479 BOOL checkAccessForImplicitValueTypeCtor /* = FALSE */)
1480{
1481 CONTRACTL
1482 {
1483 THROWS;
1484 GC_TRIGGERS;
1485 MODE_COOPERATIVE;
1486 PRECONDITION(CheckPointer(pCtx));
1487 PRECONDITION(CheckPointer(pClassMT));
1488 }
1489 CONTRACTL_END;
1490
1491 // Walking the stack is expensive so don't try to get the caller here.
1492 // ClassLoader::CanAccessClass will retrieve the caller when necessary
1493 // and it will give an interop (NULL) caller a pass.
1494
1495 AccessCheckOptions accessCheckOptions(pCtx->GetAccessCheckType(),
1496 NULL,
1497 !checkAccessForImplicitValueTypeCtor,
1498 pClassMT);
1499
1500 BOOL canAccess;
1501 canAccess = ClassLoader::CanAccessClass(pCtx,
1502 pClassMT,
1503 pClassMT->GetAssembly(),
1504 accessCheckOptions);
1505
1506 if (!canAccess)
1507 {
1508 _ASSERTE(checkAccessForImplicitValueTypeCtor);
1509 COMPlusThrow(kMethodAccessException, W("Arg_MethodAccessException"));
1510 }
1511}
1512
1513//
1514// Ensure that a method is accessible, throwing a MethodAccessException if not
1515//
1516// Arguments:
1517// pCtx - current reflection context
1518// pTargetMT - class containing the method being checked
1519// pInstanceMT - instance being accessed if the method is not static
1520// pTargetMethod - method to check access to
1521//
1522// Return Value:
1523// Nothing - throws an exception if access is not allowed
1524//
1525
1526// static
1527void InvokeUtil::CheckAccessMethod(RefSecContext *pCtx,
1528 MethodTable *pTargetMT,
1529 MethodTable *pInstanceMT,
1530 MethodDesc *pTargetMethod)
1531{
1532 CONTRACTL
1533 {
1534 THROWS;
1535 GC_TRIGGERS;
1536 MODE_ANY;
1537 PRECONDITION(CheckPointer(pTargetMT));
1538 PRECONDITION(CheckPointer(pTargetMethod));
1539 }
1540 CONTRACTL_END;
1541
1542 AccessCheckOptions accessCheckOptions(pCtx->GetAccessCheckType(),
1543 NULL,
1544 TRUE,
1545 pTargetMethod);
1546 InvokeUtil::CheckAccess(pCtx,
1547 pTargetMT,
1548 pInstanceMT,
1549 pTargetMethod,
1550 NULL,
1551 accessCheckOptions);
1552}
1553
1554//
1555// Ensure that a field is accessible, throwing a FieldAccessException if not
1556//
1557// Arguments:
1558// pCtx - current reflection context
1559// pTargetMT - class containing the field being checked
1560// pInstanceMT - instance being accessed if the field is not static
1561// pTargetField - field to check access to
1562//
1563// Return Value:
1564// Nothing - throws an exception if access is not allowed
1565//
1566
1567// static
1568void InvokeUtil::CheckAccessField(RefSecContext *pCtx,
1569 MethodTable *pTargetMT,
1570 MethodTable *pInstanceMT,
1571 FieldDesc *pTargetField)
1572{
1573 CONTRACTL
1574 {
1575 THROWS;
1576 GC_TRIGGERS;
1577 MODE_ANY;
1578 PRECONDITION(CheckPointer(pTargetMT));
1579 PRECONDITION(CheckPointer(pTargetField));
1580 }
1581 CONTRACTL_END;
1582
1583 AccessCheckOptions accessCheckOptions(pCtx->GetAccessCheckType(),
1584 NULL,
1585 TRUE,
1586 pTargetField);
1587
1588 InvokeUtil::CheckAccess(pCtx,
1589 pTargetMT,
1590 pInstanceMT,
1591 NULL,
1592 pTargetField,
1593 accessCheckOptions);
1594 }
1595
1596
1597//
1598// Check accessibility of a field or method.
1599//
1600// Arguments:
1601// pCtx - current reflection context
1602// pTargetMT - class containing the target being checked
1603// pInstanceMT - instance being accessed, if the field or method is non-NULL
1604// pTargetMethod - if checking access to a method, its MethodDesc
1605// pTargetField - if checking access to a field, its FieldDesc
1606// accessCheckOptions - CanAccess flags indicating how security demands should be done
1607//
1608// Return Value:
1609// Nothing - throws an exception if access is not allowed
1610//
1611// Notes:
1612// accessCheckOptions is required to be setup to throw if the target is inaccessable
1613
1614// static
1615void InvokeUtil::CheckAccess(RefSecContext *pCtx,
1616 MethodTable *pTargetMT,
1617 MethodTable *pInstanceMT,
1618 MethodDesc *pTargetMethod,
1619 FieldDesc *pTargetField,
1620 const AccessCheckOptions &accessCheckOptions)
1621{
1622 CONTRACTL
1623 {
1624 THROWS;
1625 GC_TRIGGERS;
1626 MODE_ANY;
1627 PRECONDITION(CheckPointer(pTargetMT));
1628 PRECONDITION((pTargetMethod != NULL) ^ (pTargetField != NULL));
1629 }
1630 CONTRACTL_END;
1631
1632 DWORD dwAttr = pTargetMethod != NULL ? pTargetMethod->GetAttrs() : pTargetField->GetAttributes();
1633
1634 // Walking the stack is expensive so don't try to get the caller here.
1635 // ClassLoader::CanAccess will retrieve the caller when necessary
1636 // and it will give an interop (NULL) caller a pass.
1637
1638 BOOL canAccess;
1639
1640 canAccess = ClassLoader::CanAccess(pCtx,
1641 pTargetMT,
1642 pTargetMT->GetAssembly(),
1643 dwAttr,
1644 pTargetMethod,
1645 pTargetField,
1646 accessCheckOptions);
1647 if (pInstanceMT && canAccess)
1648 {
1649 if (pTargetMethod != NULL ? IsMdFamily(dwAttr) : IsFdFamily(dwAttr))
1650 {
1651 MethodTable* pCallerMT = pCtx->GetCallerMT();
1652
1653 if (pCallerMT != NULL &&
1654 !ClassLoader::CanAccessFamilyVerification(pCallerMT, pInstanceMT))
1655 {
1656 canAccess = accessCheckOptions.DemandMemberAccessOrFail(pCtx,
1657 pInstanceMT,
1658 TRUE /*visibilityCheck*/);
1659 }
1660 }
1661 }
1662
1663 // If this assert fires, ensure that accessCheckOptions was setup to throw if the target was inaccessable.
1664 _ASSERTE(canAccess);
1665}
1666
1667/*static*/
1668AccessCheckOptions::AccessCheckType InvokeUtil::GetInvocationAccessCheckType(BOOL targetRemoted /*= FALSE*/)
1669{
1670 LIMITED_METHOD_CONTRACT;
1671
1672 if (targetRemoted)
1673 return AccessCheckOptions::kMemberAccess;
1674
1675 // Ignore transparency so that reflection invocation is consistenct with LCG.
1676 // There is no security concern because we are in Full Trust.
1677 return AccessCheckOptions::kRestrictedMemberAccessNoTransparency;
1678}
1679
1680#endif // CROSSGEN_COMPILE
1681