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 | |
21 | typedef InlineFactory<InlineSString<64>, 16> SStringFactory; |
22 | |
23 | /*static*/ |
24 | TypeHandle 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*/ |
43 | HRESULT 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 | |
80 | ErrExit: |
81 | return hr; |
82 | } |
83 | |
84 | /*static*/ |
85 | void 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*/ |
113 | void 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*/ |
137 | CustomAttributeManagedValues 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*/ |
197 | HRESULT 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 | |
215 | ErrExit: |
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 | |
224 | HRESULT 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 | |
311 | ErrExit: |
312 | return hr; |
313 | } |
314 | |
315 | /*static*/ |
316 | HRESULT 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 | |
341 | ErrExit: |
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*/ |
353 | HRESULT 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 | |
474 | ErrExit: |
475 | return hr; |
476 | } |
477 | |
478 | /*static*/ |
479 | HRESULT 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 | |
506 | ErrExit: |
507 | return hr; |
508 | } |
509 | |
510 | FCIMPL5(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 | } |
666 | FCIMPLEND |
667 | |
668 | |
669 | FCIMPL2(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 | } |
728 | FCIMPLEND |
729 | |
730 | FCIMPL6(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 | } |
860 | FCIMPLEND |
861 | |
862 | FCIMPL5(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 | } |
902 | FCIMPLEND |
903 | |
904 | |
905 | FCIMPL7(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 | } |
1061 | FCIMPLEND |
1062 | |
1063 | /*static*/ |
1064 | TypeHandle 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*/ |
1161 | int 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*/ |
1194 | template < typename T > |
1195 | BOOL 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*/ |
1226 | void 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*/ |
1348 | ARG_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 | |