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#include "common.h"
7#include "customattribute.h"
8#include "invokeutil.h"
9#include "method.hpp"
10#include "threads.h"
11#include "excep.h"
12#include "corerror.h"
13#include "classnames.h"
14#include "fcall.h"
15#include "assemblynative.hpp"
16#include "typeparse.h"
17#include "reflectioninvocation.h"
18#include "runtimehandles.h"
19#include "typestring.h"
20
21typedef InlineFactory<InlineSString<64>, 16> SStringFactory;
22
23/*static*/
24TypeHandle Attribute::GetTypeForEnum(LPCUTF8 szEnumName, COUNT_T cbEnumName, DomainAssembly* pDomainAssembly)
25{
26 CONTRACTL
27 {
28 PRECONDITION(CheckPointer(pDomainAssembly));
29 PRECONDITION(CheckPointer(szEnumName));
30 PRECONDITION(cbEnumName);
31 THROWS;
32 GC_TRIGGERS;
33 MODE_ANY;
34 }
35 CONTRACTL_END;
36
37 StackScratchBuffer buff;
38 StackSString sszEnumName(SString::Utf8, szEnumName, cbEnumName);
39 return TypeName::GetTypeUsingCASearchRules(sszEnumName.GetUTF8(buff), pDomainAssembly->GetAssembly());
40}
41
42/*static*/
43HRESULT Attribute::ParseCaType(
44 CustomAttributeParser &ca,
45 CaType* pCaType,
46 DomainAssembly* pDomainAssembly,
47 StackSString* ss)
48{
49 WRAPPER_NO_CONTRACT;
50
51 HRESULT hr = S_OK;
52
53 IfFailGo(::ParseEncodedType(ca, pCaType));
54
55 if (pCaType->tag == SERIALIZATION_TYPE_ENUM ||
56 (pCaType->tag == SERIALIZATION_TYPE_SZARRAY && pCaType->arrayType == SERIALIZATION_TYPE_ENUM ))
57 {
58 TypeHandle th = Attribute::GetTypeForEnum(pCaType->szEnumName, pCaType->cEnumName, pDomainAssembly);
59
60 if (!th.IsNull() && th.IsEnum())
61 {
62 pCaType->enumType = (CorSerializationType)th.GetVerifierCorElementType();
63
64 // The assembly qualified name of th might not equal pCaType->szEnumName.
65 // e.g. th could be "MyEnum, MyAssembly, Version=4.0.0.0" while
66 // pCaType->szEnumName is "MyEnum, MyAssembly, Version=3.0.0.0"
67 if (ss)
68 {
69 DWORD format = TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly;
70 TypeString::AppendType(*ss, th, format);
71 }
72 }
73 else
74 {
75 MAKE_WIDEPTR_FROMUTF8N(pWideStr, pCaType->szEnumName, pCaType->cEnumName)
76 IfFailGo(PostError(META_E_CA_UNEXPECTED_TYPE, wcslen(pWideStr), pWideStr));
77 }
78 }
79
80ErrExit:
81 return hr;
82}
83
84/*static*/
85void Attribute::SetBlittableCaValue(CustomAttributeValue* pVal, CaValue* pCaVal, BOOL* pbAllBlittableCa)
86{
87 WRAPPER_NO_CONTRACT;
88
89 CorSerializationType type = pCaVal->type.tag;
90
91 pVal->m_type.m_tag = pCaVal->type.tag;
92 pVal->m_type.m_arrayType = pCaVal->type.arrayType;
93 pVal->m_type.m_enumType = pCaVal->type.enumType;
94 pVal->m_rawValue = 0;
95
96 if (type == SERIALIZATION_TYPE_STRING ||
97 type == SERIALIZATION_TYPE_SZARRAY ||
98 type == SERIALIZATION_TYPE_TYPE)
99 {
100 *pbAllBlittableCa = FALSE;
101 }
102 else
103 {
104 // Enum arg -> Object param
105 if (type == SERIALIZATION_TYPE_ENUM && pCaVal->type.cEnumName)
106 *pbAllBlittableCa = FALSE;
107
108 pVal->m_rawValue = pCaVal->i8;
109 }
110}
111
112/*static*/
113void Attribute::SetManagedValue(CustomAttributeManagedValues gc, CustomAttributeValue* pValue)
114{
115 WRAPPER_NO_CONTRACT;
116
117 CorSerializationType type = pValue->m_type.m_tag;
118
119 if (type == SERIALIZATION_TYPE_TYPE || type == SERIALIZATION_TYPE_STRING)
120 {
121 SetObjectReference((OBJECTREF*)&pValue->m_enumOrTypeName, gc.string, GetAppDomain());
122 }
123 else if (type == SERIALIZATION_TYPE_ENUM)
124 {
125 SetObjectReference((OBJECTREF*)&pValue->m_type.m_enumName, gc.string, GetAppDomain());
126 }
127 else if (type == SERIALIZATION_TYPE_SZARRAY)
128 {
129 SetObjectReference((OBJECTREF*)&pValue->m_value, gc.array, GetAppDomain());
130
131 if (pValue->m_type.m_arrayType == SERIALIZATION_TYPE_ENUM)
132 SetObjectReference((OBJECTREF*)&pValue->m_type.m_enumName, gc.string, GetAppDomain());
133 }
134}
135
136/*static*/
137CustomAttributeManagedValues Attribute::GetManagedCaValue(CaValue* pCaVal)
138{
139 WRAPPER_NO_CONTRACT;
140
141 CustomAttributeManagedValues gc;
142 ZeroMemory(&gc, sizeof(gc));
143 GCPROTECT_BEGIN(gc)
144 {
145 CorSerializationType type = pCaVal->type.tag;
146
147 if (type == SERIALIZATION_TYPE_ENUM)
148 {
149 gc.string = StringObject::NewString(pCaVal->type.szEnumName, pCaVal->type.cEnumName);
150 }
151 else if (type == SERIALIZATION_TYPE_STRING)
152 {
153 gc.string = NULL;
154
155 if (pCaVal->str.pStr)
156 gc.string = StringObject::NewString(pCaVal->str.pStr, pCaVal->str.cbStr);
157 }
158 else if (type == SERIALIZATION_TYPE_TYPE)
159 {
160 gc.string = StringObject::NewString(pCaVal->str.pStr, pCaVal->str.cbStr);
161 }
162 else if (type == SERIALIZATION_TYPE_SZARRAY)
163 {
164 CorSerializationType arrayType = pCaVal->type.arrayType;
165 ULONG length = pCaVal->arr.length;
166 BOOL bAllBlittableCa = arrayType != SERIALIZATION_TYPE_ENUM;
167
168 if (arrayType == SERIALIZATION_TYPE_ENUM)
169 gc.string = StringObject::NewString(pCaVal->type.szEnumName, pCaVal->type.cEnumName);
170
171 if (length != (ULONG)-1)
172 {
173 gc.array = (CaValueArrayREF)AllocateValueSzArray(MscorlibBinder::GetClass(CLASS__CUSTOM_ATTRIBUTE_ENCODED_ARGUMENT), length);
174 CustomAttributeValue* pValues = gc.array->GetDirectPointerToNonObjectElements();
175
176 for (COUNT_T i = 0; i < length; i ++)
177 Attribute::SetBlittableCaValue(&pValues[i], &pCaVal->arr[i], &bAllBlittableCa);
178
179 if (!bAllBlittableCa)
180 {
181 for (COUNT_T i = 0; i < length; i ++)
182 {
183 CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaVal->arr[i]);
184 Attribute::SetManagedValue(
185 managedCaValue,
186 &gc.array->GetDirectPointerToNonObjectElements()[i]);
187 }
188 }
189 }
190 }
191 }
192 GCPROTECT_END();
193 return gc;
194}
195
196/*static*/
197HRESULT Attribute::ParseAttributeArgumentValues(
198 void* pCa,
199 INT32 cCa,
200 CaValueArrayFactory* pCaValueArrayFactory,
201 CaArg* pCaArgs,
202 COUNT_T cArgs,
203 CaNamedArg* pCaNamedArgs,
204 COUNT_T cNamedArgs,
205 DomainAssembly* pDomainAssembly)
206{
207 WRAPPER_NO_CONTRACT;
208
209 HRESULT hr = S_OK;
210 CustomAttributeParser cap(pCa, cCa);
211
212 IfFailGo(Attribute::ParseCaCtorArgs(cap, pCaArgs, cArgs, pCaValueArrayFactory, pDomainAssembly));
213 IfFailGo(Attribute::ParseCaNamedArgs(cap, pCaNamedArgs, cNamedArgs, pCaValueArrayFactory, pDomainAssembly));
214
215ErrExit:
216 return hr;
217}
218
219//---------------------------------------------------------------------------------------
220//
221// Helper to parse the values for the ctor argument list and the named argument list.
222//
223
224HRESULT Attribute::ParseCaValue(
225 CustomAttributeParser &ca,
226 CaValue* pCaArg,
227 CaType* pCaParam,
228 CaValueArrayFactory* pCaValueArrayFactory,
229 DomainAssembly* pDomainAssembly)
230{
231 CONTRACTL
232 {
233 PRECONDITION(CheckPointer(pCaArg));
234 PRECONDITION(CheckPointer(pCaParam));
235 PRECONDITION(CheckPointer(pCaValueArrayFactory));
236 THROWS;
237 }
238 CONTRACTL_END;
239
240 HRESULT hr = S_OK;
241 CorSerializationType underlyingType;
242 CaType elementType;
243
244 if (pCaParam->tag == SERIALIZATION_TYPE_TAGGED_OBJECT)
245 IfFailGo(Attribute::ParseCaType(ca, &pCaArg->type, pDomainAssembly));
246 else
247 pCaArg->type = *pCaParam;
248
249 underlyingType = pCaArg->type.tag == SERIALIZATION_TYPE_ENUM ? pCaArg->type.enumType : pCaArg->type.tag;
250
251 // Grab the value.
252 switch (underlyingType)
253 {
254 case SERIALIZATION_TYPE_BOOLEAN:
255 case SERIALIZATION_TYPE_I1:
256 case SERIALIZATION_TYPE_U1:
257 IfFailGo(ca.GetU1(&pCaArg->u1));
258 break;
259
260 case SERIALIZATION_TYPE_CHAR:
261 case SERIALIZATION_TYPE_I2:
262 case SERIALIZATION_TYPE_U2:
263 IfFailGo(ca.GetU2(&pCaArg->u2));
264 break;
265
266 case SERIALIZATION_TYPE_I4:
267 case SERIALIZATION_TYPE_U4:
268 IfFailGo(ca.GetU4(&pCaArg->u4));
269 break;
270
271 case SERIALIZATION_TYPE_I8:
272 case SERIALIZATION_TYPE_U8:
273 IfFailGo(ca.GetU8(&pCaArg->u8));
274 break;
275
276 case SERIALIZATION_TYPE_R4:
277 IfFailGo(ca.GetR4(&pCaArg->r4));
278 break;
279
280 case SERIALIZATION_TYPE_R8:
281 IfFailGo(ca.GetR8(&pCaArg->r8));
282 break;
283
284 case SERIALIZATION_TYPE_STRING:
285 case SERIALIZATION_TYPE_TYPE:
286 IfFailGo(ca.GetString(&pCaArg->str.pStr, &pCaArg->str.cbStr));
287 break;
288
289 case SERIALIZATION_TYPE_SZARRAY:
290 UINT32 len;
291 IfFailGo(ca.GetU4(&len));
292 pCaArg->arr.length = len;
293 pCaArg->arr.pSArray = NULL;
294 if (pCaArg->arr.length == (ULONG)-1)
295 break;
296
297 IfNullGo(pCaArg->arr.pSArray = pCaValueArrayFactory->Create());
298 elementType.Init(pCaArg->type.arrayType, SERIALIZATION_TYPE_UNDEFINED,
299 pCaArg->type.enumType, pCaArg->type.szEnumName, pCaArg->type.cEnumName);
300 for (ULONG i = 0; i < pCaArg->arr.length; i++)
301 IfFailGo(Attribute::ParseCaValue(ca, &*pCaArg->arr.pSArray->Append(), &elementType, pCaValueArrayFactory, pDomainAssembly));
302
303 break;
304
305 default:
306 // The format of the custom attribute record is invalid.
307 hr = E_FAIL;
308 break;
309 } // End switch
310
311ErrExit:
312 return hr;
313}
314
315/*static*/
316HRESULT Attribute::ParseCaCtorArgs(
317 CustomAttributeParser &ca,
318 CaArg* pArgs,
319 ULONG cArgs,
320 CaValueArrayFactory* pCaValueArrayFactory,
321 DomainAssembly* pDomainAssembly)
322{
323 WRAPPER_NO_CONTRACT;
324
325 HRESULT hr = S_OK; // A result.
326 ULONG ix; // Loop control.
327
328 // If there is a blob, check the prolog.
329 if (FAILED(ca.ValidateProlog()))
330 {
331 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
332 }
333
334 // For each expected arg...
335 for (ix=0; ix<cArgs; ++ix)
336 {
337 CaArg* pArg = &pArgs[ix];
338 IfFailGo(Attribute::ParseCaValue(ca, &pArg->val, &pArg->type, pCaValueArrayFactory, pDomainAssembly));
339 }
340
341ErrExit:
342 return hr;
343}
344
345//---------------------------------------------------------------------------------------
346//
347// Because ParseKnowCaNamedArgs MD cannot have VM dependency, we have our own implementation here:
348// 1. It needs to load the assemblies that contain the enum types for the named arguments,
349// 2. It Compares the enum type name with that of the loaded enum type, not the one in the CA record.
350//
351
352/*static*/
353HRESULT Attribute::ParseCaNamedArgs(
354 CustomAttributeParser &ca,
355 CaNamedArg *pNamedParams,
356 ULONG cNamedParams,
357 CaValueArrayFactory* pCaValueArrayFactory,
358 DomainAssembly* pDomainAssembly)
359{
360 CONTRACTL {
361 PRECONDITION(CheckPointer(pCaValueArrayFactory));
362 PRECONDITION(CheckPointer(pDomainAssembly));
363 THROWS;
364 } CONTRACTL_END;
365
366 HRESULT hr = S_OK;
367 ULONG ixParam;
368 INT32 ixArg;
369 INT16 cActualArgs;
370 CaNamedArgCtor namedArg;
371 CaNamedArg* pNamedParam;
372
373 // Get actual count of named arguments.
374 if (FAILED(ca.GetI2(&cActualArgs)))
375 cActualArgs = 0; // Everett behavior
376
377 for (ixParam = 0; ixParam < cNamedParams; ixParam++)
378 pNamedParams[ixParam].val.type.tag = SERIALIZATION_TYPE_UNDEFINED;
379
380 // For each named argument...
381 for (ixArg = 0; ixArg < cActualArgs; ixArg++)
382 {
383 // Field or property?
384 IfFailGo(ca.GetTag(&namedArg.propertyOrField));
385 if (namedArg.propertyOrField != SERIALIZATION_TYPE_FIELD && namedArg.propertyOrField != SERIALIZATION_TYPE_PROPERTY)
386 IfFailGo(PostError(META_E_CA_INVALID_ARGTYPE));
387
388 // Get argument type information
389 CaType* pNamedArgType = &namedArg.type;
390 StackSString ss;
391 IfFailGo(Attribute::ParseCaType(ca, pNamedArgType, pDomainAssembly, &ss));
392
393 LPCSTR szLoadedEnumName = NULL;
394 StackScratchBuffer buff;
395
396 if (pNamedArgType->tag == SERIALIZATION_TYPE_ENUM ||
397 (pNamedArgType->tag == SERIALIZATION_TYPE_SZARRAY && pNamedArgType->arrayType == SERIALIZATION_TYPE_ENUM ))
398 {
399 szLoadedEnumName = ss.GetUTF8(buff);
400 }
401
402 // Get name of Arg.
403 if (FAILED(ca.GetNonEmptyString(&namedArg.szName, &namedArg.cName)))
404 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
405
406 // Match arg by name and type
407 for (ixParam = 0; ixParam < cNamedParams; ixParam++)
408 {
409 pNamedParam = &pNamedParams[ixParam];
410
411 // Match type
412 if (pNamedParam->type.tag != SERIALIZATION_TYPE_TAGGED_OBJECT)
413 {
414 if (namedArg.type.tag != pNamedParam->type.tag)
415 continue;
416
417 // Match array type
418 if (namedArg.type.tag == SERIALIZATION_TYPE_SZARRAY &&
419 pNamedParam->type.arrayType != SERIALIZATION_TYPE_TAGGED_OBJECT &&
420 namedArg.type.arrayType != pNamedParam->type.arrayType)
421 continue;
422 }
423
424 // Match name (and its length to avoid substring matching)
425 if ((pNamedParam->cName != namedArg.cName) ||
426 (strncmp(pNamedParam->szName, namedArg.szName, namedArg.cName) != 0))
427 {
428 continue;
429 }
430
431 // If enum, match enum name.
432 if (pNamedParam->type.tag == SERIALIZATION_TYPE_ENUM ||
433 (pNamedParam->type.tag == SERIALIZATION_TYPE_SZARRAY && pNamedParam->type.arrayType == SERIALIZATION_TYPE_ENUM ))
434 {
435 // pNamedParam->type.szEnumName: module->CA record->ctor token->loaded type->field/property->field/property type->field/property type name
436 // namedArg.type.szEnumName: module->CA record->named arg->enum type name
437 // szLoadedEnumName: module->CA record->named arg->enum type name->loaded enum type->loaded enum type name
438
439 // Comparing pNamedParam->type.szEnumName against namedArg.type.szEnumName could fail if we loaded a different version
440 // of the enum type than the one specified in the CA record. So we are comparing it against szLoadedEnumName instead.
441 if (strncmp(pNamedParam->type.szEnumName, szLoadedEnumName, pNamedParam->type.cEnumName) != 0)
442 continue;
443
444 if (namedArg.type.enumType != pNamedParam->type.enumType)
445 {
446 MAKE_WIDEPTR_FROMUTF8N(pWideStr, pNamedParam->type.szEnumName, pNamedParam->type.cEnumName)
447 IfFailGo(PostError(META_E_CA_UNEXPECTED_TYPE, wcslen(pWideStr), pWideStr));
448 }
449
450 // TODO: For now assume the property\field array size is correct - later we should verify this
451 }
452
453 // Found a match.
454 break;
455 }
456
457 // Better have found an argument.
458 if (ixParam == cNamedParams)
459 {
460 MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
461 IfFailGo(PostError(META_E_CA_UNKNOWN_ARGUMENT, wcslen(pWideStr), pWideStr));
462 }
463
464 // Argument had better not have been seen already.
465 if (pNamedParams[ixParam].val.type.tag != SERIALIZATION_TYPE_UNDEFINED)
466 {
467 MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
468 IfFailGo(PostError(META_E_CA_REPEATED_ARG, wcslen(pWideStr), pWideStr));
469 }
470
471 IfFailGo(Attribute::ParseCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type, pCaValueArrayFactory, pDomainAssembly));
472 }
473
474ErrExit:
475 return hr;
476}
477
478/*static*/
479HRESULT Attribute::InitCaType(CustomAttributeType* pType, Factory<SString>* pSstringFactory, Factory<StackScratchBuffer>* pStackScratchBufferFactory, CaType* pCaType)
480{
481 CONTRACTL {
482 THROWS;
483 PRECONDITION(CheckPointer(pType));
484 PRECONDITION(CheckPointer(pSstringFactory));
485 PRECONDITION(CheckPointer(pStackScratchBufferFactory));
486 PRECONDITION(CheckPointer(pCaType));
487 } CONTRACTL_END;
488
489 HRESULT hr = S_OK;
490
491 SString* psszName = NULL;
492 StackScratchBuffer* scratchBuffer = NULL;
493
494 IfNullGo(psszName = pSstringFactory->Create());
495 IfNullGo(scratchBuffer = pStackScratchBufferFactory->Create());
496
497 psszName->Set(pType->m_enumName == NULL ? NULL : pType->m_enumName->GetBuffer());
498
499 pCaType->Init(
500 pType->m_tag,
501 pType->m_arrayType,
502 pType->m_enumType,
503 psszName->GetUTF8(*scratchBuffer),
504 (ULONG)psszName->GetCount());
505
506ErrExit:
507 return hr;
508}
509
510FCIMPL5(VOID, Attribute::ParseAttributeArguments, void* pCa, INT32 cCa,
511 CaArgArrayREF* ppCustomAttributeArguments,
512 CaNamedArgArrayREF* ppCustomAttributeNamedArguments,
513 AssemblyBaseObject* pAssemblyUNSAFE)
514{
515 FCALL_CONTRACT;
516
517 ASSEMBLYREF refAssembly = (ASSEMBLYREF)ObjectToOBJECTREF(pAssemblyUNSAFE);
518
519 HELPER_METHOD_FRAME_BEGIN_1(refAssembly)
520 {
521 DomainAssembly *pDomainAssembly = refAssembly->GetDomainAssembly();
522
523 struct
524 {
525 CustomAttributeArgument* pArgs;
526 CustomAttributeNamedArgument* pNamedArgs;
527 } gc;
528
529 gc.pArgs = NULL;
530 gc.pNamedArgs = NULL;
531
532 HRESULT hr = S_OK;
533
534 GCPROTECT_BEGININTERIOR(gc);
535
536 BOOL bAllBlittableCa = TRUE;
537 COUNT_T cArgs = 0;
538 COUNT_T cNamedArgs = 0;
539 CaArg* pCaArgs = NULL;
540 CaNamedArg* pCaNamedArgs = NULL;
541#ifdef __GNUC__
542 // When compiling under GCC we have to use the -fstack-check option to ensure we always spot stack
543 // overflow. But this option is intolerant of locals growing too large, so we have to cut back a bit
544 // on what we can allocate inline here. Leave the Windows versions alone to retain the perf benefits
545 // since we don't have the same constraints.
546 NewHolder<CaValueArrayFactory> pCaValueArrayFactory = new InlineFactory<SArray<CaValue>, 4>();
547 InlineFactory<StackScratchBuffer, 4> stackScratchBufferFactory;
548 InlineFactory<SString, 4> sstringFactory;
549#else // __GNUC__
550
551 // Preallocate 4 elements in each of the following factories for optimal performance.
552 // 4 is enough for 4 typed args or 2 named args which are enough for 99% of the cases.
553
554 // SArray<CaValue> is only needed if a argument is an array, don't preallocate any memory as arrays are rare.
555
556 // Need one per (ctor or named) arg + one per array element
557 InlineFactory<SArray<CaValue>, 4> caValueArrayFactory;
558 InlineFactory<SArray<CaValue>, 4> *pCaValueArrayFactory = &caValueArrayFactory;
559
560 // Need one StackScratchBuffer per ctor arg and two per named arg
561 InlineFactory<StackScratchBuffer, 4> stackScratchBufferFactory;
562
563 // Need one SString per ctor arg and two per named arg
564 InlineFactory<SString, 4> sstringFactory;
565#endif // __GNUC__
566
567 cArgs = (*ppCustomAttributeArguments)->GetNumComponents();
568
569 if (cArgs)
570 {
571 gc.pArgs = (*ppCustomAttributeArguments)->GetDirectPointerToNonObjectElements();
572
573 size_t size = sizeof(CaArg) * cArgs;
574 if ((size / sizeof(CaArg)) != cArgs) // uint over/underflow
575 IfFailGo(E_INVALIDARG);
576 pCaArgs = (CaArg*)_alloca(size);
577
578 for (COUNT_T i = 0; i < cArgs; i ++)
579 {
580 CaType caType;
581 IfFailGo(Attribute::InitCaType(&gc.pArgs[i].m_type, &sstringFactory, &stackScratchBufferFactory, &caType));
582
583 pCaArgs[i].Init(caType);
584 }
585 }
586
587 cNamedArgs = (*ppCustomAttributeNamedArguments)->GetNumComponents();
588
589 if (cNamedArgs)
590 {
591 gc.pNamedArgs = (*ppCustomAttributeNamedArguments)->GetDirectPointerToNonObjectElements();
592
593 size_t size = sizeof(CaNamedArg) * cNamedArgs;
594 if ((size / sizeof(CaNamedArg)) != cNamedArgs) // uint over/underflow
595 IfFailGo(E_INVALIDARG);
596 pCaNamedArgs = (CaNamedArg*)_alloca(size);
597
598 for (COUNT_T i = 0; i < cNamedArgs; i ++)
599 {
600 CustomAttributeNamedArgument* pNamedArg = &gc.pNamedArgs[i];
601
602 CaType caType;
603 IfFailGo(Attribute::InitCaType(&pNamedArg->m_type, &sstringFactory, &stackScratchBufferFactory, &caType));
604
605 SString* psszName = NULL;
606 IfNullGo(psszName = sstringFactory.Create());
607
608 psszName->Set(pNamedArg->m_argumentName->GetBuffer());
609
610 StackScratchBuffer* scratchBuffer = NULL;
611 IfNullGo(scratchBuffer = stackScratchBufferFactory.Create());
612
613 pCaNamedArgs[i].Init(
614 psszName->GetUTF8(*scratchBuffer),
615 pNamedArg->m_propertyOrField,
616 caType);
617 }
618 }
619
620 // This call maps the named parameters (fields and arguments) and ctor parameters with the arguments in the CA record
621 // and retrieve their values.
622 IfFailGo(Attribute::ParseAttributeArgumentValues(pCa, cCa, pCaValueArrayFactory, pCaArgs, cArgs, pCaNamedArgs, cNamedArgs, pDomainAssembly));
623
624 for (COUNT_T i = 0; i < cArgs; i ++)
625 Attribute::SetBlittableCaValue(&gc.pArgs[i].m_value, &pCaArgs[i].val, &bAllBlittableCa);
626
627 for (COUNT_T i = 0; i < cNamedArgs; i ++)
628 Attribute::SetBlittableCaValue(&gc.pNamedArgs[i].m_value, &pCaNamedArgs[i].val, &bAllBlittableCa);
629
630 if (!bAllBlittableCa)
631 {
632 for (COUNT_T i = 0; i < cArgs; i ++)
633 {
634 CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaArgs[i].val);
635 Attribute::SetManagedValue(managedCaValue, &(gc.pArgs[i].m_value));
636 }
637
638 for (COUNT_T i = 0; i < cNamedArgs; i++)
639 {
640 CustomAttributeManagedValues managedCaValue = Attribute::GetManagedCaValue(&pCaNamedArgs[i].val);
641 Attribute::SetManagedValue(managedCaValue, &(gc.pNamedArgs[i].m_value));
642 }
643 }
644
645 ErrExit:
646
647 ; // Need empty statement to get GCPROTECT_END below to work.
648
649 GCPROTECT_END();
650
651
652 if (hr != S_OK)
653 {
654 if ((hr == E_OUTOFMEMORY) || (hr == NTE_NO_MEMORY))
655 {
656 COMPlusThrow(kOutOfMemoryException);
657 }
658 else
659 {
660 COMPlusThrow(kCustomAttributeFormatException);
661 }
662 }
663 }
664 HELPER_METHOD_FRAME_END();
665}
666FCIMPLEND
667
668
669FCIMPL2(Object*, RuntimeTypeHandle::CreateCaInstance, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject* pCtorUNSAFE) {
670 CONTRACTL {
671 FCALL_CHECK;
672 PRECONDITION(CheckPointer(pCaTypeUNSAFE));
673 PRECONDITION(!pCaTypeUNSAFE->GetType().IsGenericVariable());
674 PRECONDITION(pCaTypeUNSAFE->GetType().IsValueType() || CheckPointer(pCtorUNSAFE));
675 }
676 CONTRACTL_END;
677
678 struct _gc
679 {
680 REFLECTCLASSBASEREF refCaType;
681 OBJECTREF o;
682 REFLECTMETHODREF refCtor;
683 } gc;
684
685 gc.refCaType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pCaTypeUNSAFE);
686 MethodTable* pCaMT = gc.refCaType->GetType().GetMethodTable();
687
688 gc.o = NULL;
689 gc.refCtor = (REFLECTMETHODREF)ObjectToOBJECTREF(pCtorUNSAFE);
690 MethodDesc *pCtor = gc.refCtor != NULL ? gc.refCtor->GetMethod() : NULL;
691
692 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
693 {
694 PRECONDITION(
695 (!pCtor && gc.refCaType->GetType().IsValueType() && !gc.refCaType->GetType().GetMethodTable()->HasDefaultConstructor()) ||
696 (pCtor == gc.refCaType->GetType().GetMethodTable()->GetDefaultConstructor()));
697
698 gc.o = pCaMT->Allocate();
699
700 if (pCtor)
701 {
702
703 ARG_SLOT args;
704
705 if (pCaMT->IsValueType())
706 {
707 MethodDescCallSite ctor(pCtor, &gc.o);
708 args = PtrToArgSlot(gc.o->UnBox());
709 ctor.CallWithValueTypes(&args);
710 }
711 else
712 {
713
714 PREPARE_NONVIRTUAL_CALLSITE_USING_METHODDESC(pCtor);
715 DECLARE_ARGHOLDER_ARRAY(CtorArgs, 1);
716 CtorArgs[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.o);
717
718 // Call the ctor...
719 CALL_MANAGED_METHOD_NORET(CtorArgs);
720 }
721
722 }
723 }
724 HELPER_METHOD_FRAME_END();
725
726 return OBJECTREFToObject(gc.o);
727}
728FCIMPLEND
729
730FCIMPL6(LPVOID, COMCustomAttribute::CreateCaObject, ReflectModuleBaseObject* pAttributedModuleUNSAFE, ReflectClassBaseObject* pCaTypeUNSAFE, ReflectMethodObject *pMethodUNSAFE, BYTE** ppBlob, BYTE* pEndBlob, INT32* pcNamedArgs)
731{
732 FCALL_CONTRACT;
733
734 struct
735 {
736 REFLECTCLASSBASEREF refCaType;
737 OBJECTREF ca;
738 REFLECTMETHODREF refCtor;
739 REFLECTMODULEBASEREF refAttributedModule;
740 } gc;
741 gc.refCaType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pCaTypeUNSAFE);
742 TypeHandle th = gc.refCaType->GetType();
743
744 gc.ca = NULL;
745 gc.refCtor = (REFLECTMETHODREF)ObjectToOBJECTREF(pMethodUNSAFE);
746 gc.refAttributedModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pAttributedModuleUNSAFE);
747
748 if(gc.refAttributedModule == NULL)
749 FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
750
751 MethodDesc* pCtorMD = gc.refCtor->GetMethod();
752
753 HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
754 {
755 MethodDescCallSite ctorCallSite(pCtorMD, th);
756 MetaSig* pSig = ctorCallSite.GetMetaSig();
757 BYTE* pBlob = *ppBlob;
758
759 // get the number of arguments and allocate an array for the args
760 ARG_SLOT *args = NULL;
761 UINT cArgs = pSig->NumFixedArgs() + 1; // make room for the this pointer
762 UINT i = 1; // used to flag that we actually get the right number of arg from the blob
763
764 args = (ARG_SLOT*)_alloca(cArgs * sizeof(ARG_SLOT));
765 memset((void*)args, 0, cArgs * sizeof(ARG_SLOT));
766
767 OBJECTREF *argToProtect = (OBJECTREF*)_alloca(cArgs * sizeof(OBJECTREF));
768 memset((void*)argToProtect, 0, cArgs * sizeof(OBJECTREF));
769
770 // load the this pointer
771 argToProtect[0] = pCtorMD->GetMethodTable()->Allocate(); // this is the value to return after the ctor invocation
772
773 if (pBlob)
774 {
775 if (pBlob < pEndBlob)
776 {
777 if (pBlob + 2 > pEndBlob)
778 {
779 COMPlusThrow(kCustomAttributeFormatException);
780 }
781 INT16 prolog = GET_UNALIGNED_VAL16(pBlob);
782 if (prolog != 1)
783 COMPlusThrow(kCustomAttributeFormatException);
784 pBlob += 2;
785 }
786
787 if (cArgs > 1)
788 {
789 GCPROTECT_ARRAY_BEGIN(*argToProtect, cArgs);
790 {
791 // loop through the args
792 for (i = 1; i < cArgs; i++) {
793 CorElementType type = pSig->NextArg();
794 if (type == ELEMENT_TYPE_END)
795 break;
796 BOOL bObjectCreated = FALSE;
797 TypeHandle th = pSig->GetLastTypeHandleThrowing();
798 if (th.IsArray())
799 // get the array element
800 th = th.AsArray()->GetArrayElementTypeHandle();
801 ARG_SLOT data = GetDataFromBlob(pCtorMD->GetAssembly(), (CorSerializationType)type, th, &pBlob, pEndBlob, gc.refAttributedModule->GetModule(), &bObjectCreated);
802 if (bObjectCreated)
803 argToProtect[i] = ArgSlotToObj(data);
804 else
805 args[i] = data;
806 }
807 }
808 GCPROTECT_END();
809
810 // We have borrowed the signature from MethodDescCallSite. We have to put it back into the initial position
811 // because of that's where MethodDescCallSite expects to find it below.
812 pSig->Reset();
813
814 for (i = 1; i < cArgs; i++)
815 {
816 if (argToProtect[i] != NULL)
817 {
818 _ASSERTE(args[i] == NULL);
819 args[i] = ObjToArgSlot(argToProtect[i]);
820 }
821 }
822 }
823 }
824 args[0] = ObjToArgSlot(argToProtect[0]);
825
826 if (i != cArgs)
827 COMPlusThrow(kCustomAttributeFormatException);
828
829 // check if there are any named properties to invoke,
830 // if so set the by ref int passed in to point
831 // to the blob position where name properties start
832 *pcNamedArgs = 0;
833
834 if (pBlob && pBlob != pEndBlob)
835 {
836 if (pBlob + 2 > pEndBlob)
837 COMPlusThrow(kCustomAttributeFormatException);
838
839 *pcNamedArgs = GET_UNALIGNED_VAL16(pBlob);
840
841 pBlob += 2;
842 }
843
844 *ppBlob = pBlob;
845
846 if (*pcNamedArgs == 0 && pBlob != pEndBlob)
847 COMPlusThrow(kCustomAttributeFormatException);
848
849 // make the invocation to the ctor
850 gc.ca = ArgSlotToObj(args[0]);
851 if (pCtorMD->GetMethodTable()->IsValueType())
852 args[0] = PtrToArgSlot(OBJECTREFToObject(gc.ca)->UnBox());
853
854 ctorCallSite.CallWithValueTypes(args);
855 }
856 HELPER_METHOD_FRAME_END();
857
858 return OBJECTREFToObject(gc.ca);
859}
860FCIMPLEND
861
862FCIMPL5(VOID, COMCustomAttribute::ParseAttributeUsageAttribute, PVOID pData, ULONG cData, ULONG* pTargets, CLR_BOOL* pInherited, CLR_BOOL* pAllowMultiple)
863{
864 FCALL_CONTRACT;
865
866 int inherited = 0;
867 int allowMultiple = 1;
868
869 BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException));
870 {
871 CustomAttributeParser ca(pData, cData);
872
873 CaArg args[1];
874 args[0].InitEnum(SERIALIZATION_TYPE_I4, 0);
875 if (FAILED(::ParseKnownCaArgs(ca, args, lengthof(args))))
876 {
877 HELPER_METHOD_FRAME_BEGIN_0();
878 COMPlusThrow(kCustomAttributeFormatException);
879 HELPER_METHOD_FRAME_END();
880 }
881
882 *pTargets = args[0].val.u4;
883
884 CaNamedArg namedArgs[2];
885 CaType namedArgTypes[2];
886 namedArgTypes[inherited].Init(SERIALIZATION_TYPE_BOOLEAN);
887 namedArgTypes[allowMultiple].Init(SERIALIZATION_TYPE_BOOLEAN);
888 namedArgs[inherited].Init("Inherited", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[inherited], TRUE);
889 namedArgs[allowMultiple].Init("AllowMultiple", SERIALIZATION_TYPE_PROPERTY, namedArgTypes[allowMultiple], FALSE);
890 if (FAILED(::ParseKnownCaNamedArgs(ca, namedArgs, lengthof(namedArgs))))
891 {
892 HELPER_METHOD_FRAME_BEGIN_0();
893 COMPlusThrow(kCustomAttributeFormatException);
894 HELPER_METHOD_FRAME_END();
895 }
896
897 *pInherited = namedArgs[inherited].val.boolean == TRUE;
898 *pAllowMultiple = namedArgs[allowMultiple].val.boolean == TRUE;
899 }
900 END_SO_INTOLERANT_CODE;
901}
902FCIMPLEND
903
904
905FCIMPL7(void, COMCustomAttribute::GetPropertyOrFieldData, ReflectModuleBaseObject *pModuleUNSAFE, BYTE** ppBlobStart, BYTE* pBlobEnd, STRINGREF* pName, CLR_BOOL* pbIsProperty, OBJECTREF* pType, OBJECTREF* value)
906{
907 FCALL_CONTRACT;
908
909 BYTE* pBlob = *ppBlobStart;
910 *pType = NULL;
911
912 REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
913
914 if(refModule == NULL)
915 FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
916
917 Module *pModule = refModule->GetModule();
918
919 HELPER_METHOD_FRAME_BEGIN_1(refModule);
920 {
921 Assembly *pCtorAssembly = NULL;
922
923 MethodTable *pMTValue = NULL;
924 CorSerializationType arrayType = SERIALIZATION_TYPE_BOOLEAN;
925 BOOL bObjectCreated = FALSE;
926 TypeHandle nullTH;
927
928 if (pBlob + 2 > pBlobEnd)
929 COMPlusThrow(kCustomAttributeFormatException);
930
931 // get whether it is a field or a property
932 CorSerializationType propOrField = (CorSerializationType)*pBlob;
933 pBlob++;
934 if (propOrField == SERIALIZATION_TYPE_FIELD)
935 *pbIsProperty = FALSE;
936 else if (propOrField == SERIALIZATION_TYPE_PROPERTY)
937 *pbIsProperty = TRUE;
938 else
939 COMPlusThrow(kCustomAttributeFormatException);
940
941 // get the type of the field
942 CorSerializationType fieldType = (CorSerializationType)*pBlob;
943 pBlob++;
944 if (fieldType == SERIALIZATION_TYPE_SZARRAY)
945 {
946 arrayType = (CorSerializationType)*pBlob;
947
948 if (pBlob + 1 > pBlobEnd)
949 COMPlusThrow(kCustomAttributeFormatException);
950
951 pBlob++;
952 }
953 if (fieldType == SERIALIZATION_TYPE_ENUM || arrayType == SERIALIZATION_TYPE_ENUM)
954 {
955 // get the enum type
956 ReflectClassBaseObject *pEnum =
957 (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob(
958 pCtorAssembly, SERIALIZATION_TYPE_TYPE, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)));
959
960 if (pEnum == NULL)
961 COMPlusThrow(kCustomAttributeFormatException);
962
963 _ASSERTE(bObjectCreated);
964
965 TypeHandle th = pEnum->GetType();
966 _ASSERTE(th.IsEnum());
967
968 pMTValue = th.AsMethodTable();
969 if (fieldType == SERIALIZATION_TYPE_ENUM)
970 // load the enum type to pass it back
971 *pType = th.GetManagedClassObject();
972 else
973 nullTH = th;
974 }
975
976 //
977 // get the string representing the field/property name
978 *pName = ArgSlotToString(GetDataFromBlob(
979 pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated));
980 _ASSERTE(bObjectCreated || *pName == NULL);
981
982 // create the object and return it
983 switch (fieldType)
984 {
985 case SERIALIZATION_TYPE_TAGGED_OBJECT:
986 *pType = g_pObjectClass->GetManagedClassObject();
987 case SERIALIZATION_TYPE_TYPE:
988 case SERIALIZATION_TYPE_STRING:
989 *value = ArgSlotToObj(GetDataFromBlob(
990 pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated));
991 _ASSERTE(bObjectCreated || *value == NULL);
992
993 if (*value == NULL)
994 {
995 // load the proper type so that code in managed knows which property to load
996 if (fieldType == SERIALIZATION_TYPE_STRING)
997 *pType = MscorlibBinder::GetElementType(ELEMENT_TYPE_STRING)->GetManagedClassObject();
998 else if (fieldType == SERIALIZATION_TYPE_TYPE)
999 *pType = MscorlibBinder::GetClass(CLASS__TYPE)->GetManagedClassObject();
1000 }
1001 break;
1002 case SERIALIZATION_TYPE_SZARRAY:
1003 {
1004 int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated);
1005
1006 if (arraySize != -1)
1007 {
1008 _ASSERTE(!bObjectCreated);
1009 if (arrayType == SERIALIZATION_TYPE_STRING)
1010 nullTH = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_STRING));
1011 else if (arrayType == SERIALIZATION_TYPE_TYPE)
1012 nullTH = TypeHandle(MscorlibBinder::GetClass(CLASS__TYPE));
1013 else if (arrayType == SERIALIZATION_TYPE_TAGGED_OBJECT)
1014 nullTH = TypeHandle(g_pObjectClass);
1015 ReadArray(pCtorAssembly, arrayType, arraySize, nullTH, &pBlob, pBlobEnd, pModule, (BASEARRAYREF*)value);
1016 }
1017 if (*value == NULL)
1018 {
1019 TypeHandle arrayTH;
1020 switch (arrayType)
1021 {
1022 case SERIALIZATION_TYPE_STRING:
1023 arrayTH = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_STRING));
1024 break;
1025 case SERIALIZATION_TYPE_TYPE:
1026 arrayTH = TypeHandle(MscorlibBinder::GetClass(CLASS__TYPE));
1027 break;
1028 case SERIALIZATION_TYPE_TAGGED_OBJECT:
1029 arrayTH = TypeHandle(g_pObjectClass);
1030 break;
1031 default:
1032 if (SERIALIZATION_TYPE_BOOLEAN <= arrayType && arrayType <= SERIALIZATION_TYPE_R8)
1033 arrayTH = TypeHandle(MscorlibBinder::GetElementType((CorElementType)arrayType));
1034 }
1035 if (!arrayTH.IsNull())
1036 {
1037 arrayTH = ClassLoader::LoadArrayTypeThrowing(arrayTH);
1038 *pType = arrayTH.GetManagedClassObject();
1039 }
1040 }
1041 break;
1042 }
1043 default:
1044 if (SERIALIZATION_TYPE_BOOLEAN <= fieldType && fieldType <= SERIALIZATION_TYPE_R8)
1045 pMTValue = MscorlibBinder::GetElementType((CorElementType)fieldType);
1046 else if(fieldType == SERIALIZATION_TYPE_ENUM)
1047 fieldType = (CorSerializationType)pMTValue->GetInternalCorElementType();
1048 else
1049 COMPlusThrow(kCustomAttributeFormatException);
1050
1051 ARG_SLOT val = GetDataFromBlob(pCtorAssembly, fieldType, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated);
1052 _ASSERTE(!bObjectCreated);
1053
1054 *value = pMTValue->Box((void*)ArgSlotEndianessFixup(&val, pMTValue->GetNumInstanceFieldBytes()));
1055 }
1056
1057 *ppBlobStart = pBlob;
1058 }
1059 HELPER_METHOD_FRAME_END();
1060}
1061FCIMPLEND
1062
1063/*static*/
1064TypeHandle COMCustomAttribute::GetTypeHandleFromBlob(Assembly *pCtorAssembly,
1065 CorSerializationType objType,
1066 BYTE **pBlob,
1067 const BYTE *endBlob,
1068 Module *pModule)
1069{
1070 CONTRACTL
1071 {
1072 THROWS;
1073 }
1074 CONTRACTL_END;
1075
1076 // we must box which means we must get the method table, switch again on the element type
1077 MethodTable *pMTType = NULL;
1078 TypeHandle nullTH;
1079 TypeHandle RtnTypeHnd;
1080
1081 switch ((DWORD)objType) {
1082 case SERIALIZATION_TYPE_BOOLEAN:
1083 case SERIALIZATION_TYPE_I1:
1084 case SERIALIZATION_TYPE_U1:
1085 case SERIALIZATION_TYPE_CHAR:
1086 case SERIALIZATION_TYPE_I2:
1087 case SERIALIZATION_TYPE_U2:
1088 case SERIALIZATION_TYPE_I4:
1089 case SERIALIZATION_TYPE_U4:
1090 case SERIALIZATION_TYPE_R4:
1091 case SERIALIZATION_TYPE_I8:
1092 case SERIALIZATION_TYPE_U8:
1093 case SERIALIZATION_TYPE_R8:
1094 case SERIALIZATION_TYPE_STRING:
1095 pMTType = MscorlibBinder::GetElementType((CorElementType)objType);
1096 RtnTypeHnd = TypeHandle(pMTType);
1097 break;
1098
1099 case ELEMENT_TYPE_CLASS:
1100 pMTType = MscorlibBinder::GetClass(CLASS__TYPE);
1101 RtnTypeHnd = TypeHandle(pMTType);
1102 break;
1103
1104 case SERIALIZATION_TYPE_TAGGED_OBJECT:
1105 pMTType = g_pObjectClass;
1106 RtnTypeHnd = TypeHandle(pMTType);
1107 break;
1108
1109 case SERIALIZATION_TYPE_TYPE:
1110 {
1111 int size = GetStringSize(pBlob, endBlob);
1112 if (size == -1)
1113 return nullTH;
1114
1115 if ((size+1 <= 1) || (size > endBlob - *pBlob))
1116 COMPlusThrow(kCustomAttributeFormatException);
1117
1118 LPUTF8 szName = (LPUTF8)_alloca(size + 1);
1119 memcpy(szName, *pBlob, size);
1120 *pBlob += size;
1121 szName[size] = 0;
1122
1123 RtnTypeHnd = TypeName::GetTypeUsingCASearchRules(szName, pModule->GetAssembly(), NULL, FALSE);
1124 break;
1125 }
1126
1127 case SERIALIZATION_TYPE_ENUM:
1128 {
1129 // get the enum type
1130 BOOL isObject = FALSE;
1131 ReflectClassBaseObject *pType = (ReflectClassBaseObject*)OBJECTREFToObject(ArgSlotToObj(GetDataFromBlob(pCtorAssembly,
1132 SERIALIZATION_TYPE_TYPE,
1133 nullTH,
1134 pBlob,
1135 endBlob,
1136 pModule,
1137 &isObject)));
1138 if (pType != NULL)
1139 {
1140 _ASSERTE(isObject);
1141 RtnTypeHnd = pType->GetType();
1142 _ASSERTE((objType == SERIALIZATION_TYPE_ENUM) ? RtnTypeHnd.GetMethodTable()->IsEnum() : TRUE);
1143 }
1144 else
1145 {
1146 RtnTypeHnd = TypeHandle();
1147 }
1148 break;
1149 }
1150
1151 default:
1152 COMPlusThrow(kCustomAttributeFormatException);
1153 }
1154
1155 return RtnTypeHnd;
1156}
1157
1158// retrieve the string size in a CA blob. Advance the blob pointer to point to
1159// the beginning of the string immediately following the size
1160/*static*/
1161int COMCustomAttribute::GetStringSize(BYTE **pBlob, const BYTE *endBlob)
1162{
1163 CONTRACTL
1164 {
1165 THROWS;
1166 }
1167 CONTRACTL_END;
1168
1169 if (*pBlob >= endBlob )
1170 { // No buffer at all, or buffer overrun
1171 COMPlusThrow(kCustomAttributeFormatException);
1172 }
1173
1174 if (**pBlob == 0xFF)
1175 { // Special case null string.
1176 ++(*pBlob);
1177 return -1;
1178 }
1179
1180 ULONG ulSize;
1181 if (FAILED(CPackedLen::SafeGetData((BYTE const *)*pBlob, (BYTE const *)endBlob, (ULONG *)&ulSize, (BYTE const **)pBlob)))
1182 {
1183 COMPlusThrow(kCustomAttributeFormatException);
1184 }
1185
1186 return (int)ulSize;
1187}
1188
1189// copy the values of an array of integers from a CA blob
1190// (i.e., always stored in little-endian, and needs not be aligned).
1191// Returns TRUE on success, FALSE if the blob was not big enough.
1192// Advances *pBlob by the amount copied.
1193/*static*/
1194template < typename T >
1195BOOL COMCustomAttribute::CopyArrayVAL(BASEARRAYREF pArray, int nElements, BYTE **pBlob, const BYTE *endBlob)
1196{
1197 int sizeData; // = size * 2; with integer overflow check
1198 if (!ClrSafeInt<int>::multiply(nElements, sizeof(T), sizeData))
1199 return FALSE;
1200 if (*pBlob + sizeData < *pBlob) // integer overflow check
1201 return FALSE;
1202 if (*pBlob + sizeData > endBlob)
1203 return FALSE;
1204#if BIGENDIAN
1205 T *ptDest = reinterpret_cast<T *>(pArray->GetDataPtr());
1206 for (int iElement = 0; iElement < nElements; iElement++)
1207 {
1208 T tValue;
1209 BYTE *pbSrc = *pBlob + iElement * sizeof(T);
1210 BYTE *pbDest = reinterpret_cast<BYTE *>(&tValue);
1211 for (size_t iByte = 0; iByte < sizeof(T); iByte++)
1212 {
1213 pbDest[sizeof(T) - 1 - iByte] = pbSrc[iByte];
1214 }
1215 ptDest[iElement] = tValue;
1216 }
1217#else // BIGENDIAN
1218 memcpyNoGCRefs(pArray->GetDataPtr(), *pBlob, sizeData);
1219#endif // BIGENDIAN
1220 *pBlob += sizeData;
1221 return TRUE;
1222}
1223
1224// read the whole array as a chunk
1225/*static*/
1226void COMCustomAttribute::ReadArray(Assembly *pCtorAssembly,
1227 CorSerializationType arrayType,
1228 int size,
1229 TypeHandle th,
1230 BYTE **pBlob,
1231 const BYTE *endBlob,
1232 Module *pModule,
1233 BASEARRAYREF *pArray)
1234{
1235 CONTRACTL
1236 {
1237 THROWS;
1238 }
1239 CONTRACTL_END;
1240
1241 ARG_SLOT element = 0;
1242
1243 switch ((DWORD)arrayType) {
1244 case SERIALIZATION_TYPE_BOOLEAN:
1245 case SERIALIZATION_TYPE_I1:
1246 case SERIALIZATION_TYPE_U1:
1247 *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size);
1248 if (!CopyArrayVAL<BYTE>(*pArray, size, pBlob, endBlob))
1249 goto badBlob;
1250 break;
1251
1252 case SERIALIZATION_TYPE_CHAR:
1253 case SERIALIZATION_TYPE_I2:
1254 case SERIALIZATION_TYPE_U2:
1255 {
1256 *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size);
1257 if (!CopyArrayVAL<UINT16>(*pArray, size, pBlob, endBlob))
1258 goto badBlob;
1259 break;
1260 }
1261 case SERIALIZATION_TYPE_I4:
1262 case SERIALIZATION_TYPE_U4:
1263 case SERIALIZATION_TYPE_R4:
1264 {
1265 *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size);
1266 if (!CopyArrayVAL<UINT32>(*pArray, size, pBlob, endBlob))
1267 goto badBlob;
1268 break;
1269 }
1270 case SERIALIZATION_TYPE_I8:
1271 case SERIALIZATION_TYPE_U8:
1272 case SERIALIZATION_TYPE_R8:
1273 {
1274 *pArray = (BASEARRAYREF)AllocatePrimitiveArray((CorElementType)arrayType, size);
1275 if (!CopyArrayVAL<UINT64>(*pArray, size, pBlob, endBlob))
1276 goto badBlob;
1277 break;
1278 }
1279 case ELEMENT_TYPE_CLASS:
1280 case SERIALIZATION_TYPE_TYPE:
1281 case SERIALIZATION_TYPE_STRING:
1282 case SERIALIZATION_TYPE_SZARRAY:
1283 case SERIALIZATION_TYPE_TAGGED_OBJECT:
1284 {
1285 BOOL isObject;
1286
1287 // If we haven't figured out the type of the array, throw bad blob exception
1288 if (th.IsNull())
1289 goto badBlob;
1290
1291 *pArray = (BASEARRAYREF)AllocateObjectArray(size, th);
1292 if (arrayType == SERIALIZATION_TYPE_SZARRAY)
1293 // switch the th to be the proper one
1294 th = th.AsArray()->GetArrayElementTypeHandle();
1295 for (int i = 0; i < size; i++) {
1296 element = GetDataFromBlob(pCtorAssembly, arrayType, th, pBlob, endBlob, pModule, &isObject);
1297 _ASSERTE(isObject || element == NULL);
1298 ((PTRARRAYREF)(*pArray))->SetAt(i, ArgSlotToObj(element));
1299 }
1300 break;
1301 }
1302
1303 case SERIALIZATION_TYPE_ENUM:
1304 {
1305 INT32 bounds = size;
1306
1307 // If we haven't figured out the type of the array, throw bad blob exception
1308 if (th.IsNull())
1309 goto badBlob;
1310
1311 unsigned elementSize = th.GetSize();
1312 TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(th);
1313 if (arrayHandle.IsNull())
1314 goto badBlob;
1315 *pArray = (BASEARRAYREF)AllocateArrayEx(arrayHandle, &bounds, 1);
1316 BOOL fSuccess;
1317 switch (elementSize)
1318 {
1319 case 1:
1320 fSuccess = CopyArrayVAL<BYTE>(*pArray, size, pBlob, endBlob);
1321 break;
1322 case 2:
1323 fSuccess = CopyArrayVAL<UINT16>(*pArray, size, pBlob, endBlob);
1324 break;
1325 case 4:
1326 fSuccess = CopyArrayVAL<UINT32>(*pArray, size, pBlob, endBlob);
1327 break;
1328 case 8:
1329 fSuccess = CopyArrayVAL<UINT64>(*pArray, size, pBlob, endBlob);
1330 break;
1331 default:
1332 fSuccess = FALSE;
1333 }
1334 if (!fSuccess)
1335 goto badBlob;
1336 break;
1337 }
1338
1339 default:
1340 badBlob:
1341 COMPlusThrow(kCustomAttributeFormatException);
1342 }
1343
1344}
1345
1346// get data out of the blob according to a CorElementType
1347/*static*/
1348ARG_SLOT COMCustomAttribute::GetDataFromBlob(Assembly *pCtorAssembly,
1349 CorSerializationType type,
1350 TypeHandle th,
1351 BYTE **pBlob,
1352 const BYTE *endBlob,
1353 Module *pModule,
1354 BOOL *bObjectCreated)
1355{
1356 CONTRACTL
1357 {
1358 THROWS;
1359 }
1360 CONTRACTL_END;
1361
1362 ARG_SLOT retValue = 0;
1363 *bObjectCreated = FALSE;
1364 TypeHandle nullTH;
1365 TypeHandle typeHnd;
1366
1367 switch ((DWORD)type) {
1368
1369 case SERIALIZATION_TYPE_BOOLEAN:
1370 case SERIALIZATION_TYPE_I1:
1371 case SERIALIZATION_TYPE_U1:
1372 if (*pBlob + 1 <= endBlob) {
1373 retValue = (ARG_SLOT)**pBlob;
1374 *pBlob += 1;
1375 break;
1376 }
1377 goto badBlob;
1378
1379 case SERIALIZATION_TYPE_CHAR:
1380 case SERIALIZATION_TYPE_I2:
1381 case SERIALIZATION_TYPE_U2:
1382 if (*pBlob + 2 <= endBlob) {
1383 retValue = (ARG_SLOT)GET_UNALIGNED_VAL16(*pBlob);
1384 *pBlob += 2;
1385 break;
1386 }
1387 goto badBlob;
1388
1389 case SERIALIZATION_TYPE_I4:
1390 case SERIALIZATION_TYPE_U4:
1391 case SERIALIZATION_TYPE_R4:
1392 if (*pBlob + 4 <= endBlob) {
1393 retValue = (ARG_SLOT)GET_UNALIGNED_VAL32(*pBlob);
1394 *pBlob += 4;
1395 break;
1396 }
1397 goto badBlob;
1398
1399 case SERIALIZATION_TYPE_I8:
1400 case SERIALIZATION_TYPE_U8:
1401 case SERIALIZATION_TYPE_R8:
1402 if (*pBlob + 8 <= endBlob) {
1403 retValue = (ARG_SLOT)GET_UNALIGNED_VAL64(*pBlob);
1404 *pBlob += 8;
1405 break;
1406 }
1407 goto badBlob;
1408
1409 case SERIALIZATION_TYPE_STRING:
1410 stringType:
1411 {
1412 int size = GetStringSize(pBlob, endBlob);
1413 *bObjectCreated = TRUE;
1414 if (size > 0) {
1415 if (*pBlob + size < *pBlob) // integer overflow check
1416 goto badBlob;
1417 if (*pBlob + size > endBlob)
1418 goto badBlob;
1419 retValue = ObjToArgSlot(StringObject::NewString((LPCUTF8)*pBlob, size));
1420 *pBlob += size;
1421 }
1422 else if (size == 0)
1423 retValue = ObjToArgSlot(StringObject::NewString(0));
1424 else
1425 *bObjectCreated = FALSE;
1426
1427 break;
1428 }
1429
1430 // this is coming back from sig but it's not a serialization type,
1431 // essentialy the type in the blob and the type in the sig don't match
1432 case ELEMENT_TYPE_VALUETYPE:
1433 {
1434 if (!th.IsEnum())
1435 goto badBlob;
1436 CorSerializationType enumType = (CorSerializationType)th.GetInternalCorElementType();
1437 BOOL cannotBeObject = FALSE;
1438 retValue = GetDataFromBlob(pCtorAssembly, enumType, nullTH, pBlob, endBlob, pModule, &cannotBeObject);
1439 _ASSERTE(!cannotBeObject);
1440 break;
1441 }
1442
1443 // this is coming back from sig but it's not a serialization type,
1444 // essentialy the type in the blob and the type in the sig don't match
1445 case ELEMENT_TYPE_CLASS:
1446 if (th.IsArray())
1447 goto typeArray;
1448 else {
1449 MethodTable *pMT = th.AsMethodTable();
1450 if (pMT == g_pStringClass)
1451 goto stringType;
1452 else if (pMT == g_pObjectClass)
1453 goto typeObject;
1454 else if (MscorlibBinder::IsClass(pMT, CLASS__TYPE))
1455 goto typeType;
1456 }
1457
1458 goto badBlob;
1459
1460 case SERIALIZATION_TYPE_TYPE:
1461 typeType:
1462 {
1463 typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_TYPE, pBlob, endBlob, pModule);
1464 if (!typeHnd.IsNull())
1465 retValue = ObjToArgSlot(typeHnd.GetManagedClassObject());
1466 *bObjectCreated = TRUE;
1467 break;
1468 }
1469
1470 // this is coming back from sig but it's not a serialization type,
1471 // essentialy the type in the blob and the type in the sig don't match
1472 case ELEMENT_TYPE_OBJECT:
1473 case SERIALIZATION_TYPE_TAGGED_OBJECT:
1474 typeObject:
1475 {
1476 // get the byte representing the real type and call GetDataFromBlob again
1477 if (*pBlob + 1 > endBlob)
1478 goto badBlob;
1479 CorSerializationType objType = (CorSerializationType)**pBlob;
1480 *pBlob += 1;
1481 switch (objType) {
1482 case SERIALIZATION_TYPE_SZARRAY:
1483 {
1484 if (*pBlob + 1 > endBlob)
1485 goto badBlob;
1486 CorSerializationType arrayType = (CorSerializationType)**pBlob;
1487 *pBlob += 1;
1488 if (arrayType == SERIALIZATION_TYPE_TYPE)
1489 arrayType = (CorSerializationType)ELEMENT_TYPE_CLASS;
1490 // grab the array type and make a type handle for it
1491 nullTH = GetTypeHandleFromBlob(pCtorAssembly, arrayType, pBlob, endBlob, pModule);
1492 }
1493 case SERIALIZATION_TYPE_TYPE:
1494 case SERIALIZATION_TYPE_STRING:
1495 // notice that the nullTH is actually not null in the array case (see case above)
1496 retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated);
1497 _ASSERTE(*bObjectCreated || retValue == 0);
1498 break;
1499 case SERIALIZATION_TYPE_ENUM:
1500 {
1501 //
1502 // get the enum type
1503 typeHnd = GetTypeHandleFromBlob(pCtorAssembly, SERIALIZATION_TYPE_ENUM, pBlob, endBlob, pModule);
1504 _ASSERTE(typeHnd.IsTypeDesc() == false);
1505
1506 // ok we have the class, now we go and read the data
1507 MethodTable *pMT = typeHnd.AsMethodTable();
1508 PREFIX_ASSUME(pMT != NULL);
1509 CorSerializationType objNormType = (CorSerializationType)pMT->GetInternalCorElementType();
1510 BOOL isObject = FALSE;
1511 retValue = GetDataFromBlob(pCtorAssembly, objNormType, nullTH, pBlob, endBlob, pModule, &isObject);
1512 _ASSERTE(!isObject);
1513 retValue= ObjToArgSlot(pMT->Box((void*)&retValue));
1514 *bObjectCreated = TRUE;
1515 break;
1516 }
1517 default:
1518 {
1519 // the common primitive type case. We need to box the primitive
1520 typeHnd = GetTypeHandleFromBlob(pCtorAssembly, objType, pBlob, endBlob, pModule);
1521 _ASSERTE(typeHnd.IsTypeDesc() == false);
1522 retValue = GetDataFromBlob(pCtorAssembly, objType, nullTH, pBlob, endBlob, pModule, bObjectCreated);
1523 _ASSERTE(!*bObjectCreated);
1524 retValue= ObjToArgSlot(typeHnd.AsMethodTable()->Box((void*)&retValue));
1525 *bObjectCreated = TRUE;
1526 break;
1527 }
1528 }
1529 break;
1530 }
1531
1532 case SERIALIZATION_TYPE_SZARRAY:
1533 typeArray:
1534 {
1535 // read size
1536 BOOL isObject = FALSE;
1537 int size = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, pBlob, endBlob, pModule, &isObject);
1538 _ASSERTE(!isObject);
1539
1540 if (size != -1) {
1541 CorSerializationType arrayType;
1542 if (th.IsEnum())
1543 arrayType = SERIALIZATION_TYPE_ENUM;
1544 else
1545 arrayType = (CorSerializationType)th.GetInternalCorElementType();
1546
1547 BASEARRAYREF array = NULL;
1548 GCPROTECT_BEGIN(array);
1549 ReadArray(pCtorAssembly, arrayType, size, th, pBlob, endBlob, pModule, &array);
1550 retValue = ObjToArgSlot(array);
1551 GCPROTECT_END();
1552 }
1553 *bObjectCreated = TRUE;
1554 break;
1555 }
1556
1557 default:
1558 badBlob:
1559 //<TODO> generate a reasonable text string ("invalid blob or constructor")</TODO>
1560 COMPlusThrow(kCustomAttributeFormatException);
1561 }
1562
1563 return retValue;
1564}
1565