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// CustAttr_Emit.cpp
6//
7
8//
9// Implementation for the meta data custom attribute emit code (code:IMetaDataEmit).
10//
11//*****************************************************************************
12#include "stdafx.h"
13#include "regmeta.h"
14#include "metadata.h"
15#include "corerror.h"
16#include "mdutil.h"
17#include "rwutil.h"
18#include "mdlog.h"
19#include "importhelper.h"
20#include "mdperf.h"
21#include "posterror.h"
22#include "cahlprinternal.h"
23#include "custattr.h"
24#include "corhdr.h"
25#include <metamodelrw.h>
26
27#ifdef FEATURE_METADATA_EMIT
28
29//*****************************************************************************
30//*****************************************************************************
31// Support for "Pseudo Custom Attributes"
32
33
34//*****************************************************************************
35// Enumeration of known custom attributes.
36//*****************************************************************************
37#define KnownCaList() \
38 KnownCa(UNKNOWN) \
39 KnownCa(DllImportAttribute) \
40 KnownCa(GuidAttribute) \
41 KnownCa(ComImportAttribute) \
42 KnownCa(InterfaceTypeAttribute) \
43 KnownCa(ClassInterfaceAttribute) \
44 KnownCa(SerializableAttribute) \
45 KnownCa(NonSerializedAttribute) \
46 KnownCa(MethodImplAttribute1) \
47 KnownCa(MethodImplAttribute2) \
48 KnownCa(MethodImplAttribute3) \
49 KnownCa(MarshalAsAttribute1) \
50 KnownCa(MarshalAsAttribute2) \
51 KnownCa(PreserveSigAttribute) \
52 KnownCa(InAttribute) \
53 KnownCa(OutAttribute) \
54 KnownCa(OptionalAttribute) \
55 KnownCa(StructLayoutAttribute1) \
56 KnownCa(StructLayoutAttribute2) \
57 KnownCa(FieldOffsetAttribute) \
58 KnownCa(TypeLibVersionAttribute) \
59 KnownCa(ComCompatibleVersionAttribute) \
60 KnownCa(SpecialNameAttribute) \
61 KnownCa(AllowPartiallyTrustedCallersAttribute) \
62 KnownCa(WindowsRuntimeImportAttribute) \
63
64// Ids for the CA's. CA_DllImportAttribute, etc.
65#define KnownCa(x) CA_##x,
66enum {
67 KnownCaList()
68 CA_COUNT
69};
70
71
72//*****************************************************************************
73// Properties of the known custom attributes.
74//
75// These tables describe the known custom attributes. For each custom
76// attribute, we know the namespace and name of the custom attribute,
77// the types to which the CA applies, the ctor args, and possible named
78// args. There is a flag which specifies whether the custom attribute
79// should be kept, in addition to any processing done with the data.
80//*****************************************************************************
81const BOOL bKEEPCA = TRUE;
82const BOOL bDONTKEEPCA = FALSE;
83const BOOL bMATCHBYSIG = TRUE;
84const BOOL bMATCHBYNAME = FALSE;
85
86struct KnownCaProp
87{
88 LPCUTF8 szNamespace; // Namespace of the custom attribute.
89 LPCUTF8 szName; // Name of the custom attribute.
90 const mdToken * rTypes; // Types that the CA applies to.
91 BOOL bKeepCa; // Keep the CA after processing?
92 const CaArg * pArgs; // List of ctor argument descriptors.
93 ULONG cArgs; // Count of ctor argument descriptors.
94 const CaNamedArg * pNamedArgs; // List of named arg descriptors.
95 ULONG cNamedArgs; // Count of named arg descriptors.
96 BOOL bMatchBySig; // For overloads; match by sig, not just name.
97 // WARNING: All overloads need the flag!
98};
99
100// Recognized targets for known custom attributes.
101// If Target includes mdtAssembly, then make sure to include mdtTypeRef as well,
102// aLink uses mdtTypeRef target temporarily for assembly target attributes
103const mdToken DllImportTargets[] = {mdtMethodDef, (ULONG32) -1};
104const mdToken GuidTargets[] = {mdtTypeDef, mdtTypeRef, mdtModule, mdtAssembly, (ULONG32) -1};
105const mdToken ComImportTargets[] = {mdtTypeDef, (ULONG32) -1};
106const mdToken InterfaceTypeTargets[] = {mdtTypeDef, (ULONG32) -1};
107const mdToken ClassInterfaceTargets[] = {mdtTypeDef, mdtAssembly, mdtTypeRef, (ULONG32) -1};
108const mdToken SerializableTargets[] = {mdtTypeDef, (ULONG32) -1};
109const mdToken NotInGCHeapTargets[] = {mdtTypeDef, (ULONG32) -1};
110const mdToken NonSerializedTargets[] = {mdtFieldDef, (ULONG32) -1};
111const mdToken MethodImplTargets[] = {mdtMethodDef, (ULONG32) -1};
112const mdToken MarshalTargets[] = {mdtFieldDef, mdtParamDef, mdtProperty, (ULONG32) -1};
113const mdToken PreserveSigTargets[] = {mdtMethodDef, (ULONG32) -1};
114const mdToken InOutTargets[] = {mdtParamDef, (ULONG32) -1};
115const mdToken StructLayoutTargets[] = {mdtTypeDef, (ULONG32) -1};
116const mdToken FieldOffsetTargets[] = {mdtFieldDef, (ULONG32) -1};
117const mdToken TypeLibVersionTargets[] = {mdtAssembly, mdtTypeRef,(ULONG32) -1};
118const mdToken ComCompatibleVersionTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
119const mdToken SpecialNameTargets[] = {mdtTypeDef, mdtMethodDef, mdtFieldDef, mdtProperty, mdtEvent, (ULONG32) -1};
120const mdToken AllowPartiallyTrustedCallersTargets[] = {mdtAssembly, mdtTypeRef, (ULONG32) -1};
121const mdToken WindowsRuntimeImportTargets[] = {mdtTypeDef, (ULONG32) -1};
122
123
124//#ifndef CEE_CALLCONV
125// # define CEE_CALLCONV (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS)
126//#endif
127
128#define DEFINE_CA_CTOR_ARGS(NAME) \
129 const CaArg r##NAME##Args[] = \
130 {
131#define DEFINE_CA_CTOR_ARG(TYPE) {{TYPE}},
132#define DEFINE_CA_CTOR_ARGS_END() \
133 };
134
135
136
137#define DEFINE_CA_NAMED_ARGS(NAME) \
138 const CaNamedArg r##NAME##NamedArgs[] = \
139 {
140
141#define DEFINE_CA_NAMED_ARG(NAME, PROPORFIELD, TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME) \
142 { NAME, sizeof(NAME) - 1, PROPORFIELD, { TYPE, ARRAYTYPE, ENUMTYPE, ENUMNAME, sizeof(ENUMNAME) - 1 } },
143
144#define DEFINE_CA_NAMED_PROP_I4ENUM(NAME, ENUM) \
145 DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
146#define DEFINE_CA_NAMED_FIELD_I4ENUM(NAME, ENUM) \
147 DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, SERIALIZATION_TYPE_ENUM, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_I4, ENUM)
148#define DEFINE_CA_NAMED_PROP(NAME, TYPE) \
149 DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_PROPERTY, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
150#define DEFINE_CA_NAMED_FIELD(NAME, TYPE) \
151 DEFINE_CA_NAMED_ARG(NAME, SERIALIZATION_TYPE_FIELD, TYPE, SERIALIZATION_TYPE_UNDEFINED, SERIALIZATION_TYPE_UNDEFINED, "")
152#define DEFINE_CA_NAMED_PROP_BOOL(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_BOOLEAN)
153#define DEFINE_CA_NAMED_FIELD_BOOL(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_BOOLEAN)
154#define DEFINE_CA_NAMED_PROP_STRING(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_STRING)
155#define DEFINE_CA_NAMED_FIELD_STRING(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_STRING)
156#define DEFINE_CA_NAMED_PROP_TYPE(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_TYPE)
157#define DEFINE_CA_NAMED_FIELD_TYPE(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_TYPE)
158#define DEFINE_CA_NAMED_PROP_I2(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I2)
159#define DEFINE_CA_NAMED_FIELD_I2(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I2)
160#define DEFINE_CA_NAMED_PROP_I4(NAME) DEFINE_CA_NAMED_PROP(NAME, SERIALIZATION_TYPE_I4)
161#define DEFINE_CA_NAMED_FIELD_I4(NAME) DEFINE_CA_NAMED_FIELD(NAME, SERIALIZATION_TYPE_I4)
162
163#define DEFINE_CA_NAMED_ARGS_END() \
164 };
165
166//-----------------------------------------------------------------------------
167// index 0 is used as a placeholder.
168const KnownCaProp UNKNOWNProps = {0};
169
170//-----------------------------------------------------------------------------
171// DllImport args, named args, and known attribute properties.
172DEFINE_CA_CTOR_ARGS(DllImportAttribute)
173 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
174DEFINE_CA_CTOR_ARGS_END()
175
176// NOTE: Keep this enum in sync with the array of named arguments.
177enum DllImportNamedArgs
178{
179 DI_CallingConvention,
180 DI_CharSet,
181 DI_EntryPoint,
182 DI_ExactSpelling,
183 DI_SetLastError,
184 DI_PreserveSig,
185 DI_BestFitMapping,
186 DI_ThrowOnUnmappableChar,
187 DI_COUNT
188};
189
190DEFINE_CA_NAMED_ARGS(DllImportAttribute)
191 DEFINE_CA_NAMED_FIELD_I4ENUM("CallingConvention", "System.Runtime.InteropServices.CallingConvention")
192 DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
193 DEFINE_CA_NAMED_FIELD_STRING("EntryPoint")
194 DEFINE_CA_NAMED_FIELD_BOOL("ExactSpelling")
195 DEFINE_CA_NAMED_FIELD_BOOL("SetLastError")
196 DEFINE_CA_NAMED_FIELD_BOOL("PreserveSig")
197 DEFINE_CA_NAMED_FIELD_BOOL("BestFitMapping")
198 DEFINE_CA_NAMED_FIELD_BOOL("ThrowOnUnmappableChar")
199DEFINE_CA_NAMED_ARGS_END()
200
201const KnownCaProp DllImportAttributeProps = {"System.Runtime.InteropServices", "DllImportAttribute", DllImportTargets, bDONTKEEPCA,
202 rDllImportAttributeArgs, lengthof(rDllImportAttributeArgs),
203 rDllImportAttributeNamedArgs, lengthof(rDllImportAttributeNamedArgs)};
204
205//-----------------------------------------------------------------------------
206// GUID args, named args (none), and known attribute properties.
207DEFINE_CA_CTOR_ARGS(GuidAttribute)
208 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_STRING)
209DEFINE_CA_CTOR_ARGS_END()
210
211const KnownCaProp GuidAttributeProps = {"System.Runtime.InteropServices", "GuidAttribute", GuidTargets, bKEEPCA,
212 rGuidAttributeArgs, lengthof(rGuidAttributeArgs)};
213
214//-----------------------------------------------------------------------------
215// ComImport args (none), named args (none), and known attribute properties.
216const KnownCaProp ComImportAttributeProps = {"System.Runtime.InteropServices", "ComImportAttribute", ComImportTargets};
217
218//-----------------------------------------------------------------------------
219// Interface type args, named args (none), and known attribute properties.
220DEFINE_CA_CTOR_ARGS(InterfaceTypeAttribute)
221 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
222DEFINE_CA_CTOR_ARGS_END()
223
224const KnownCaProp InterfaceTypeAttributeProps = {"System.Runtime.InteropServices", "InterfaceTypeAttribute", InterfaceTypeTargets, bKEEPCA,
225 rInterfaceTypeAttributeArgs, lengthof(rInterfaceTypeAttributeArgs)};
226
227//-----------------------------------------------------------------------------
228// Class interface type args, named args (none), and known attribute properties.
229DEFINE_CA_CTOR_ARGS(ClassInterfaceAttribute)
230 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U2)
231DEFINE_CA_CTOR_ARGS_END()
232
233const KnownCaProp ClassInterfaceAttributeProps = {"System.Runtime.InteropServices", "ClassInterfaceAttribute", ClassInterfaceTargets, bKEEPCA,
234 rClassInterfaceAttributeArgs, lengthof(rClassInterfaceAttributeArgs)};
235
236//-----------------------------------------------------------------------------
237// Serializable args (none), named args (none), and known attribute properties.
238const KnownCaProp SerializableAttributeProps = {"System", "SerializableAttribute", SerializableTargets};
239
240//-----------------------------------------------------------------------------
241// NonSerialized args (none), named args (none), and known attribute properties.
242const KnownCaProp NonSerializedAttributeProps = {"System", "NonSerializedAttribute", NonSerializedTargets};
243
244//-----------------------------------------------------------------------------
245// SpecialName args (none), named args (none), and known attribute properties.
246const KnownCaProp SpecialNameAttributeProps = {"System.Runtime.CompilerServices", "SpecialNameAttribute", SpecialNameTargets, bDONTKEEPCA};
247
248//-----------------------------------------------------------------------------
249// WindowsRuntimeImport args (none), named args (none), and known attribute properties.
250const KnownCaProp WindowsRuntimeImportAttributeProps = {"System.Runtime.InteropServices.WindowsRuntime", "WindowsRuntimeImportAttribute", WindowsRuntimeImportTargets};
251
252
253//-----------------------------------------------------------------------------
254// MethodImpl #1 args (none), named args, and known attribute properties.
255// MethodImpl #2 args (short), named args, and known attribute properties.
256// MethodImpl #3 args (enum), named args, and known attribute properties.
257// Note: first two match by signature; third by name only, because signature matching code is not
258// strong enough for enums.
259DEFINE_CA_CTOR_ARGS(MethodImplAttribute2)
260 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
261DEFINE_CA_CTOR_ARGS_END()
262
263DEFINE_CA_CTOR_ARGS(MethodImplAttribute3)
264 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
265DEFINE_CA_CTOR_ARGS_END()
266
267enum MethodImplAttributeNamedArgs
268{
269 MI_CodeType,
270 MI_COUNT
271};
272
273DEFINE_CA_NAMED_ARGS(MethodImplAttribute)
274 DEFINE_CA_NAMED_FIELD_I4ENUM("MethodCodeType", "System.Runtime.CompilerServices.MethodCodeType")
275DEFINE_CA_NAMED_ARGS_END()
276
277const KnownCaProp MethodImplAttribute1Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
278 0, 0,
279 rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
280 bMATCHBYSIG};
281const KnownCaProp MethodImplAttribute2Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
282 rMethodImplAttribute2Args, lengthof(rMethodImplAttribute2Args),
283 rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
284 bMATCHBYSIG};
285const KnownCaProp MethodImplAttribute3Props = {"System.Runtime.CompilerServices", "MethodImplAttribute", MethodImplTargets, bDONTKEEPCA,
286 rMethodImplAttribute3Args, lengthof(rMethodImplAttribute3Args),
287 rMethodImplAttributeNamedArgs, lengthof(rMethodImplAttributeNamedArgs),
288 bMATCHBYNAME};
289
290//-----------------------------------------------------------------------------
291// Marshal args, named args, and known attribute properties.
292DEFINE_CA_CTOR_ARGS(MarshalAsAttribute2)
293 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
294DEFINE_CA_CTOR_ARGS_END()
295
296DEFINE_CA_CTOR_ARGS(MarshalAsAttribute1)
297 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
298DEFINE_CA_CTOR_ARGS_END()
299
300// NOTE: Keep this enum in sync with the array of named arguments.
301enum MarshalNamedArgs
302{
303 M_ArraySubType,
304 M_SafeArraySubType,
305 M_SafeArrayUserDefinedSubType,
306 M_SizeParamIndex,
307 M_SizeConst,
308 M_MarshalType,
309 M_MarshalTypeRef,
310 M_MarshalCookie,
311 M_IidParameterIndex,
312 M_COUNT
313};
314
315DEFINE_CA_NAMED_ARGS(MarshalAsAttribute)
316 DEFINE_CA_NAMED_FIELD_I4ENUM("ArraySubType", "System.Runtime.InteropServices.UnmanagedType")
317 DEFINE_CA_NAMED_FIELD_I4ENUM("SafeArraySubType", "System.Runtime.InteropServices.VarEnum")
318 DEFINE_CA_NAMED_FIELD_TYPE("SafeArrayUserDefinedSubType")
319 DEFINE_CA_NAMED_FIELD_I2("SizeParamIndex")
320 DEFINE_CA_NAMED_FIELD_I4("SizeConst")
321 DEFINE_CA_NAMED_FIELD_STRING("MarshalType")
322 DEFINE_CA_NAMED_FIELD_TYPE("MarshalTypeRef")
323 DEFINE_CA_NAMED_FIELD_STRING("MarshalCookie")
324 DEFINE_CA_NAMED_FIELD_I4("IidParameterIndex")
325DEFINE_CA_NAMED_ARGS_END()
326
327const KnownCaProp MarshalAsAttribute1Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
328 rMarshalAsAttribute1Args, lengthof(rMarshalAsAttribute1Args),
329 rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
330 bMATCHBYSIG};
331
332const KnownCaProp MarshalAsAttribute2Props = {"System.Runtime.InteropServices", "MarshalAsAttribute", MarshalTargets, bDONTKEEPCA,
333 rMarshalAsAttribute2Args, lengthof(rMarshalAsAttribute2Args),
334 rMarshalAsAttributeNamedArgs, lengthof(rMarshalAsAttributeNamedArgs),
335 bMATCHBYNAME};
336
337//-----------------------------------------------------------------------------
338// PreserveSignature args, named args (none), and known attribute properties.
339const KnownCaProp PreserveSigAttributeProps = {"System.Runtime.InteropServices", "PreserveSigAttribute", PreserveSigTargets, bDONTKEEPCA};
340
341//-----------------------------------------------------------------------------
342// In args (none), named args (none), and known attribute properties.
343const KnownCaProp InAttributeProps = {"System.Runtime.InteropServices", "InAttribute", InOutTargets};
344
345//-----------------------------------------------------------------------------
346// Out args (none), named args (none), and known attribute properties.
347const KnownCaProp OutAttributeProps = {"System.Runtime.InteropServices", "OutAttribute", InOutTargets};
348
349//-----------------------------------------------------------------------------
350// Optional args (none), named args (none), and known attribute properties.
351const KnownCaProp OptionalAttributeProps = {"System.Runtime.InteropServices", "OptionalAttribute", InOutTargets};
352
353//-----------------------------------------------------------------------------
354// StructLayout args, named args, and known attribute properties.
355DEFINE_CA_CTOR_ARGS(StructLayoutAttribute2)
356 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
357DEFINE_CA_CTOR_ARGS_END()
358
359DEFINE_CA_CTOR_ARGS(StructLayoutAttribute1)
360 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I2)
361DEFINE_CA_CTOR_ARGS_END()
362
363// NOTE: Keep this enum in sync with the array of named arguments.
364enum StructLayoutNamedArgs
365{
366 SL_Pack,
367 SL_Size,
368 SL_CharSet,
369 SL_COUNT
370};
371
372DEFINE_CA_NAMED_ARGS(StructLayoutAttribute)
373 DEFINE_CA_NAMED_FIELD_I4("Pack")
374 DEFINE_CA_NAMED_FIELD_I4("Size")
375 DEFINE_CA_NAMED_FIELD_I4ENUM("CharSet", "System.Runtime.InteropServices.CharSet")
376DEFINE_CA_NAMED_ARGS_END()
377
378const KnownCaProp StructLayoutAttribute1Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
379 rStructLayoutAttribute1Args, lengthof(rStructLayoutAttribute1Args),
380 rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
381 bMATCHBYSIG};
382const KnownCaProp StructLayoutAttribute2Props = {"System.Runtime.InteropServices", "StructLayoutAttribute", StructLayoutTargets, bDONTKEEPCA,
383 rStructLayoutAttribute2Args, lengthof(rStructLayoutAttribute2Args),
384 rStructLayoutAttributeNamedArgs, lengthof(rStructLayoutAttributeNamedArgs),
385 bMATCHBYNAME};
386
387//-----------------------------------------------------------------------------
388// FieldOffset args, named args (none), and known attribute properties.
389DEFINE_CA_CTOR_ARGS(FieldOffsetAttribute)
390 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_U4)
391DEFINE_CA_CTOR_ARGS_END()
392
393const KnownCaProp FieldOffsetAttributeProps = {"System.Runtime.InteropServices", "FieldOffsetAttribute", FieldOffsetTargets, bDONTKEEPCA,
394 rFieldOffsetAttributeArgs, lengthof(rFieldOffsetAttributeArgs)};
395
396DEFINE_CA_CTOR_ARGS(TypeLibVersionAttribute)
397 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
398 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
399DEFINE_CA_CTOR_ARGS_END()
400
401const KnownCaProp TypeLibVersionAttributeProps = {"System.Runtime.InteropServices", "TypeLibVersionAttribute", TypeLibVersionTargets, bKEEPCA,
402 rTypeLibVersionAttributeArgs, lengthof(rTypeLibVersionAttributeArgs)};
403
404
405DEFINE_CA_CTOR_ARGS(ComCompatibleVersionAttribute)
406 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
407 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
408 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
409 DEFINE_CA_CTOR_ARG(SERIALIZATION_TYPE_I4)
410DEFINE_CA_CTOR_ARGS_END()
411
412const KnownCaProp ComCompatibleVersionAttributeProps = {"System.Runtime.InteropServices", "ComCompatibleVersionAttribute", ComCompatibleVersionTargets, bKEEPCA,
413 rComCompatibleVersionAttributeArgs, lengthof(rComCompatibleVersionAttributeArgs)};
414
415
416//-----------------------------------------------------------------------------
417// APTCA args (none), named args (none), and known attribute properties.
418const KnownCaProp AllowPartiallyTrustedCallersAttributeProps = {"System.Security", "AllowPartiallyTrustedCallersAttribute", AllowPartiallyTrustedCallersTargets, bKEEPCA};
419
420
421
422//-----------------------------------------------------------------------------
423// Array of known custom attribute properties
424#undef KnownCa
425#define KnownCa(x) &x##Props,
426const KnownCaProp * const rKnownCaProps[CA_COUNT] =
427{
428 KnownCaList()
429};
430
431//*****************************************************************************
432// Helper to turn on or off a single bit in a bitmask.
433//*****************************************************************************
434template<class T> FORCEINLINE void SetBitValue(T &bitmask, T bit, int bVal)
435{
436 if (bVal)
437 bitmask |= bit;
438 else
439 bitmask &= ~bit;
440} // template<class T> FORCEINLINE void SetBitValue()
441
442HRESULT ParseEncodedType(
443 CustomAttributeParser &ca,
444 CaType* pCaType)
445{
446 CONTRACTL
447 {
448 PRECONDITION(CheckPointer(pCaType));
449 NOTHROW;
450 }
451 CONTRACTL_END;
452
453 HRESULT hr = S_OK;
454
455 CorSerializationType* pType = &pCaType->tag;
456
457 IfFailGo(ca.GetTag(pType));
458
459 if (*pType == SERIALIZATION_TYPE_SZARRAY)
460 {
461 IfFailGo(ca.GetTag(&pCaType->arrayType));
462 pType = &pCaType->arrayType;
463 }
464
465 if (*pType == SERIALIZATION_TYPE_ENUM)
466 {
467 // We cannot determine the underlying type without loading the Enum.
468 pCaType->enumType = SERIALIZATION_TYPE_UNDEFINED;
469 IfFailGo(ca.GetNonNullString(&pCaType->szEnumName, &pCaType->cEnumName));
470 }
471
472ErrExit:
473 return hr;
474}
475
476//---------------------------------------------------------------------------------------
477//
478// Helper to parse the values for the ctor argument list and the named argument list.
479//
480
481HRESULT ParseKnownCaValue(
482 CustomAttributeParser &ca,
483 CaValue* pCaArg,
484 CaType* pCaParam)
485{
486 CONTRACTL
487 {
488 PRECONDITION(CheckPointer(pCaArg));
489 PRECONDITION(CheckPointer(pCaParam));
490 PRECONDITION(pCaParam->tag != SERIALIZATION_TYPE_TAGGED_OBJECT && pCaParam->tag != SERIALIZATION_TYPE_SZARRAY);
491 NOTHROW;
492 }
493 CONTRACTL_END;
494
495 HRESULT hr = S_OK;
496 CorSerializationType underlyingType;
497
498 pCaArg->type = *pCaParam;
499
500 underlyingType = pCaArg->type.tag == SERIALIZATION_TYPE_ENUM ? pCaArg->type.enumType : pCaArg->type.tag;
501
502 // Grab the value.
503 switch (underlyingType)
504 {
505 case SERIALIZATION_TYPE_BOOLEAN:
506 case SERIALIZATION_TYPE_I1:
507 case SERIALIZATION_TYPE_U1:
508 IfFailGo(ca.GetU1(&pCaArg->u1));
509 break;
510
511 case SERIALIZATION_TYPE_CHAR:
512 case SERIALIZATION_TYPE_I2:
513 case SERIALIZATION_TYPE_U2:
514 IfFailGo(ca.GetU2(&pCaArg->u2));
515 break;
516
517 case SERIALIZATION_TYPE_I4:
518 case SERIALIZATION_TYPE_U4:
519 IfFailGo(ca.GetU4(&pCaArg->u4));
520 break;
521
522 case SERIALIZATION_TYPE_I8:
523 case SERIALIZATION_TYPE_U8:
524 IfFailGo(ca.GetU8(&pCaArg->u8));
525 break;
526
527 case SERIALIZATION_TYPE_R4:
528 IfFailGo(ca.GetR4(&pCaArg->r4));
529 break;
530
531 case SERIALIZATION_TYPE_R8:
532 IfFailGo(ca.GetR8(&pCaArg->r8));
533 break;
534
535 case SERIALIZATION_TYPE_STRING:
536 case SERIALIZATION_TYPE_TYPE:
537 IfFailGo(ca.GetString(&pCaArg->str.pStr, &pCaArg->str.cbStr));
538 break;
539
540 default:
541 // The arguments of all known custom attributes are Type, String, Enum, or primitive types.
542 _ASSERTE(!"Unexpected internal error");
543 hr = E_FAIL;
544 break;
545 } // End switch
546
547ErrExit:
548 return hr;
549}
550
551//---------------------------------------------------------------------------------------
552//
553// Helper to parse the nanmed argument list.
554// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
555// should not have any VM dependency.
556//
557
558HRESULT ParseKnownCaNamedArgs(
559 CustomAttributeParser &ca, // The Custom Attribute blob.
560 CaNamedArg *pNamedParams, // Array of argument descriptors.
561 ULONG cNamedParams)
562{
563 WRAPPER_NO_CONTRACT;
564
565 HRESULT hr = S_OK;
566 ULONG ixParam;
567 INT32 ixArg;
568 INT16 cActualArgs;
569 CaNamedArgCtor namedArg;
570 CaNamedArg* pNamedParam;
571
572 // Get actual count of named arguments.
573 if (FAILED(ca.GetI2(&cActualArgs)))
574 cActualArgs = 0; // Everett behavior
575
576 for (ixParam = 0; ixParam < cNamedParams; ixParam++)
577 pNamedParams[ixParam].val.type.tag = SERIALIZATION_TYPE_UNDEFINED;
578
579 // For each named argument...
580 for (ixArg = 0; ixArg < cActualArgs; ixArg++)
581 {
582 // Field or property?
583 IfFailGo(ca.GetTag(&namedArg.propertyOrField));
584 if (namedArg.propertyOrField != SERIALIZATION_TYPE_FIELD && namedArg.propertyOrField != SERIALIZATION_TYPE_PROPERTY)
585 IfFailGo(PostError(META_E_CA_INVALID_ARGTYPE));
586
587 // Get argument type information
588 IfFailGo(ParseEncodedType(ca, &namedArg.type));
589
590 // Get name of Arg.
591 if (FAILED(ca.GetNonEmptyString(&namedArg.szName, &namedArg.cName)))
592 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
593
594 // Match arg by name and type
595 for (ixParam = 0; ixParam < cNamedParams; ixParam++)
596 {
597 pNamedParam = &pNamedParams[ixParam];
598
599 // Match type
600 if (pNamedParam->type.tag != SERIALIZATION_TYPE_TAGGED_OBJECT)
601 {
602 if (namedArg.type.tag != pNamedParam->type.tag)
603 continue;
604
605 // Match array type
606 if (namedArg.type.tag == SERIALIZATION_TYPE_SZARRAY &&
607 pNamedParam->type.arrayType != SERIALIZATION_TYPE_TAGGED_OBJECT &&
608 namedArg.type.arrayType != pNamedParam->type.arrayType)
609 continue;
610 }
611
612 // Match name (and its length to avoid substring matching)
613 if ((pNamedParam->cName != namedArg.cName) ||
614 (strncmp(pNamedParam->szName, namedArg.szName, namedArg.cName) != 0))
615 {
616 continue;
617 }
618
619 // If enum, match enum name.
620 if (pNamedParam->type.tag == SERIALIZATION_TYPE_ENUM ||
621 (pNamedParam->type.tag == SERIALIZATION_TYPE_SZARRAY && pNamedParam->type.arrayType == SERIALIZATION_TYPE_ENUM ))
622 {
623 if (pNamedParam->type.cEnumName > namedArg.type.cEnumName)
624 continue; // name cannot possibly match
625
626 if (strncmp(pNamedParam->type.szEnumName, namedArg.type.szEnumName, pNamedParam->type.cEnumName) != 0 ||
627 (pNamedParam->type.cEnumName < namedArg.type.cEnumName &&
628 namedArg.type.szEnumName[pNamedParam->type.cEnumName] != ','))
629 continue;
630
631 // TODO: For now assume the property\field array size is correct - later we should verify this
632 namedArg.type.enumType = pNamedParam->type.enumType;
633 }
634
635 // Found a match.
636 break;
637 }
638
639 // Better have found an argument.
640 if (ixParam == cNamedParams)
641 {
642 MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
643 IfFailGo(PostError(META_E_CA_UNKNOWN_ARGUMENT, wcslen(pWideStr), pWideStr));
644 }
645
646 // Argument had better not have been seen already.
647 if (pNamedParams[ixParam].val.type.tag != SERIALIZATION_TYPE_UNDEFINED)
648 {
649 MAKE_WIDEPTR_FROMUTF8N(pWideStr, namedArg.szName, namedArg.cName)
650 IfFailGo(PostError(META_E_CA_REPEATED_ARG, wcslen(pWideStr), pWideStr));
651 }
652
653 IfFailGo(ParseKnownCaValue(ca, &pNamedParams[ixParam].val, &namedArg.type));
654 }
655
656ErrExit:
657 return hr;
658}
659
660//---------------------------------------------------------------------------------------
661//
662// Helper to parse the ctor argument list.
663// This function is used by code:RegMeta::DefineCustomAttribute for IMetaDataEmit2 and
664// should not have any VM dependency.
665//
666
667HRESULT ParseKnownCaArgs(
668 CustomAttributeParser &ca, // The Custom Attribute blob.
669 CaArg* pArgs, // Array of argument descriptors.
670 ULONG cArgs) // Count of argument descriptors.
671{
672 WRAPPER_NO_CONTRACT;
673
674 HRESULT hr = S_OK; // A result.
675 ULONG ix; // Loop control.
676
677 // If there is a blob, check the prolog.
678 if (FAILED(ca.ValidateProlog()))
679 {
680 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
681 }
682
683 // For each expected arg...
684 for (ix=0; ix<cArgs; ++ix)
685 {
686 CaArg* pArg = &pArgs[ix];
687 IfFailGo(ParseKnownCaValue(ca, &pArg->val, &pArg->type));
688 }
689
690ErrExit:
691 return hr;
692} // ParseKnownCaArgs
693
694//*****************************************************************************
695// Create a CustomAttribute record from a blob with the specified parent.
696//*****************************************************************************
697STDMETHODIMP RegMeta::DefineCustomAttribute(
698 mdToken tkOwner, // [IN] The object to put the value on.
699 mdToken tkCtor, // [IN] Constructor of the CustomAttribute type (MemberRef/MethodDef).
700 void const *pCustomAttribute, // [IN] Custom Attribute data.
701 ULONG cbCustomAttribute, // [IN] Size of custom Attribute data.
702 mdCustomAttribute *pcv) // [OUT, OPTIONAL] Put custom Attribute token here.
703{
704#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
705 return E_NOTIMPL;
706#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
707 HRESULT hr = S_OK;
708
709 BEGIN_ENTRYPOINT_NOTHROW;
710
711 CustomAttributeRec *pRecord = NULL; // New custom Attribute record.
712 RID iRecord; // New custom Attribute RID.
713 CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
714 int ixKnown; // Index of known custom attribute.
715
716 LOG((LOGMD, "RegMeta::DefineCustomAttribute(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", tkOwner, tkCtor,
717 pCustomAttribute, cbCustomAttribute, pcv));
718 START_MD_PERF();
719 LOCKWRITE();
720
721 _ASSERTE(TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef);
722
723 if (TypeFromToken(tkOwner) == mdtCustomAttribute)
724 IfFailGo(E_INVALIDARG);
725
726 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
727
728 if (IsNilToken(tkOwner) ||
729 IsNilToken(tkCtor) ||
730 (TypeFromToken(tkCtor) != mdtMethodDef &&
731 TypeFromToken(tkCtor) != mdtMemberRef) )
732 {
733 IfFailGo(E_INVALIDARG);
734 }
735
736 // See if this is a known custom attribute.
737 IfFailGo(_IsKnownCustomAttribute(tkCtor, &ixKnown));
738 if (ixKnown != 0)
739 {
740 int bKeep = false;
741 hr = _HandleKnownCustomAttribute(tkOwner, pCustomAttribute, cbCustomAttribute, ixKnown, &bKeep);
742 if (pcv)
743 *pcv = mdCustomAttributeNil;
744 IfFailGo(hr);
745 if (!bKeep)
746 goto ErrExit;
747 }
748
749 if (((TypeFromToken(tkOwner) == mdtTypeDef) || (TypeFromToken(tkOwner) == mdtMethodDef)) &&
750 (TypeFromToken(tkCtor) == mdtMethodDef || TypeFromToken(tkCtor) == mdtMemberRef))
751 {
752 CHAR szBuffer[MAX_CLASS_NAME + 1];
753 LPSTR szName = szBuffer;
754 LPCSTR szNamespace;
755 LPCSTR szClass;
756 TypeRefRec *pTypeRefRec = NULL;
757 TypeDefRec *pTypeDefRec = NULL;
758 mdToken tkParent;
759
760 if (TypeFromToken(tkCtor) == mdtMemberRef)
761 {
762 MemberRefRec *pMemberRefRec;
763 IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMemberRefRec));
764 tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec);
765 if (TypeFromToken(tkParent) == mdtTypeRef)
766 {
767 IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
768 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
769 IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szClass));
770 ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
771 }
772 else if (TypeFromToken(tkParent) == mdtTypeDef)
773 {
774 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
775 }
776 }
777 else
778 {
779 IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
780 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
781 }
782
783 if (pTypeDefRec != NULL)
784 {
785 IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
786 IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szClass));
787 ns::MakePath(szName, sizeof(szBuffer) - 1, szNamespace, szClass);
788 }
789
790 if ((TypeFromToken(tkOwner) == mdtMethodDef) && strcmp(szName, COR_REQUIRES_SECOBJ_ATTRIBUTE_ANSI) == 0)
791 {
792 // Turn REQ_SO attribute into flag bit on the methoddef.
793 MethodRec *pMethod;
794 IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkOwner), &pMethod));
795 pMethod->AddFlags(mdRequireSecObject);
796 IfFailGo(UpdateENCLog(tkOwner));
797 goto ErrExit;
798 }
799 else if (strcmp(szName, COR_SUPPRESS_UNMANAGED_CODE_CHECK_ATTRIBUTE_ANSI) == 0)
800 {
801 // If we spot an unmanged code check suppression attribute, turn on
802 // the bit that says there's declarative security on the
803 // class/method, but still write the attribute itself.
804 if (TypeFromToken(tkOwner) == mdtTypeDef)
805 {
806 IfFailGo(_TurnInternalFlagsOn(tkOwner, tdHasSecurity));
807 }
808 else if (TypeFromToken(tkOwner) == mdtMethodDef)
809 {
810 IfFailGo(_TurnInternalFlagsOn(tkOwner, mdHasSecurity));
811 }
812 IfFailGo(UpdateENCLog(tkOwner));
813 }
814 }
815
816 IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributeRecord(&pRecord, &iRecord));
817 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Type, pRecord, tkCtor));
818 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_CustomAttribute, CustomAttributeRec::COL_Parent, pRecord, tkOwner));
819
820 IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
821
822 // Give token back to caller.
823 if (pcv != NULL)
824 *pcv = TokenFromRid(iRecord, mdtCustomAttribute);
825
826 IfFailGo(m_pStgdb->m_MiniMd.AddCustomAttributesToHash(TokenFromRid(iRecord, mdtCustomAttribute)) );
827
828 IfFailGo(UpdateENCLog(TokenFromRid(iRecord, mdtCustomAttribute)));
829
830ErrExit:
831 STOP_MD_PERF(DefineCustomAttribute);
832 END_ENTRYPOINT_NOTHROW;
833
834 return hr;
835#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
836} // RegMeta::DefineCustomAttribute
837
838//*****************************************************************************
839// Replace the blob of an existing custom attribute.
840//*****************************************************************************
841STDMETHODIMP RegMeta::SetCustomAttributeValue( // Return code.
842 mdCustomAttribute tkAttr, // [IN] The object to be Attributed.
843 void const *pCustomAttribute, // [IN] Custom Attribute data.
844 ULONG cbCustomAttribute) // [IN] Size of custom Attribute data.
845{
846#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
847 return E_NOTIMPL;
848#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
849 HRESULT hr;
850
851 BEGIN_ENTRYPOINT_NOTHROW;
852
853 CustomAttributeRec *pRecord = NULL;// Existing custom Attribute record.
854
855 START_MD_PERF();
856 LOCKWRITE();
857
858 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
859
860 _ASSERTE(TypeFromToken(tkAttr) == mdtCustomAttribute && !InvalidRid(tkAttr));
861
862 // Retrieve and update the custom value.
863 IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(RidFromToken(tkAttr), &pRecord));
864 IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_CustomAttribute, CustomAttributeRec::COL_Value, pRecord, pCustomAttribute, cbCustomAttribute));
865
866 IfFailGo(UpdateENCLog(tkAttr));
867ErrExit:
868
869 STOP_MD_PERF(SetCustomAttributeValue);
870 END_ENTRYPOINT_NOTHROW;
871
872 return hr;
873#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
874} // RegMeta::SetCustomAttributeValue
875
876//*****************************************************************************
877//*****************************************************************************
878HRESULT RegMeta::_IsKnownCustomAttribute( // S_OK, S_FALSE, or error.
879 mdToken tkCtor, // [IN] Token of custom attribute's constructor.
880 int *pca) // [OUT] Put value from KnownCustAttr enum here.
881{
882 HRESULT hr = S_OK; // A result.
883 CCustAttrHashKey sLookup; // For looking up a custom attribute.
884 CCustAttrHashKey *pFound; // Result of a lookup.
885 LPCSTR szNamespace = ""; // Namespace of custom attribute type.
886 LPCSTR szName = ""; // Name of custom attribute type.
887 TypeDefRec *pTypeDefRec = NULL; // Parent record, when a TypeDef.
888 TypeRefRec *pTypeRefRec = NULL; // Parent record, when a TypeRef.
889 CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
890 int ixCa; // Index of Known CustomAttribute, or 0.
891 int i; // Loop control.
892 mdToken tkParent;
893
894 *pca = 0;
895
896 // Only for Custom Attributes.
897 _ASSERTE(TypeFromToken(tkCtor) != mdtTypeRef && TypeFromToken(tkCtor) != mdtTypeDef);
898
899 sLookup.tkType = tkCtor;
900
901 // See if this custom attribute type has been seen before.
902 if ((pFound = m_caHash.Find(&sLookup)))
903 { // Yes, already seen.
904 *pca = pFound->ca;
905 hr = (pFound->ca == CA_UNKNOWN) ? S_FALSE : S_OK;
906 goto ErrExit;
907 }
908
909 // Hasn't been seen before. See if it is well known.
910
911 // Get the CA name.
912 if (TypeFromToken(tkCtor) == mdtMemberRef)
913 {
914 MemberRefRec *pMember;
915 IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
916 tkParent = pMiniMd->getClassOfMemberRef(pMember);
917 if (TypeFromToken(tkParent) == mdtTypeRef)
918 {
919 IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkParent), &pTypeRefRec));
920 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szNamespace));
921 IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szName));
922 }
923 else if (TypeFromToken(tkParent) == mdtTypeDef)
924 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
925 }
926 else
927 {
928 IfFailGo(pMiniMd->FindParentOfMethodHelper(tkCtor, &tkParent));
929 IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
930 }
931
932 if (pTypeDefRec)
933 {
934 IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTypeDefRec, &szNamespace));
935 IfFailGo(pMiniMd->getNameOfTypeDef(pTypeDefRec, &szName));
936 }
937
938 // Search in list of Known CAs.
939 for (ixCa=0, i=1; i<CA_COUNT; ++i)
940 {
941 if (strcmp(szName, rKnownCaProps[i]->szName) != 0)
942 continue;
943 if (strcmp(szNamespace, rKnownCaProps[i]->szNamespace) == 0)
944 {
945 // Some custom attributes have overloaded ctors. For those,
946 // see if this is the matching overload.
947 if (rKnownCaProps[i]->bMatchBySig)
948 {
949 // Name matches. Does the signature?
950 PCCOR_SIGNATURE pSig = NULL; // Signature of a method.
951 ULONG cbSig = 0; // Size of the signature.
952 ULONG cParams; // Count of signature parameters.
953 ULONG cb; // Size of an element
954 ULONG elem; // Signature element.
955 ULONG j; // Loop control.
956
957 // Get the signature.
958 if (TypeFromToken(tkCtor) == mdtMemberRef)
959 {
960 MemberRefRec *pMember;
961 IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCtor), &pMember));
962 IfFailGo(pMiniMd->getSignatureOfMemberRef(pMember, &pSig, &cbSig));
963 }
964 else
965 {
966 MethodRec *pMethod;
967 IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCtor), &pMethod));
968 IfFailGo(pMiniMd->getSignatureOfMethod(pMethod, &pSig, &cbSig));
969 }
970
971 // Skip calling convention.
972 cb = CorSigUncompressData(pSig, &elem);
973 pSig += cb;
974 cbSig -= cb;
975 // Count of params.
976 cb = CorSigUncompressData(pSig, &cParams);
977 pSig += cb;
978 cbSig -= cb;
979
980 // If param count mismatch, not the right CA.
981 if (cParams != rKnownCaProps[i]->cArgs)
982 continue;
983
984 // Count is fine, check each param. Skip return type (better be void).
985 cb = CorSigUncompressData(pSig, &elem);
986 _ASSERTE(elem == ELEMENT_TYPE_VOID);
987 pSig += cb;
988 cbSig -= cb;
989 for (j=0; j<cParams; ++j)
990 {
991 // Get next element from method signature.
992 cb = CorSigUncompressData(pSig, &elem);
993 pSig += cb;
994 cbSig -= cb;
995 if (rKnownCaProps[i]->pArgs[j].type.tag != (CorSerializationType) elem)
996 break;
997 }
998
999 // All matched?
1000 if (j != cParams)
1001 continue;
1002 }
1003 // All matched.
1004 ixCa = i;
1005 break;
1006 }
1007 }
1008
1009 // Add to hash.
1010 sLookup.ca = ixCa;
1011 pFound = m_caHash.Add(&sLookup);
1012 IfNullGo(pFound);
1013 *pFound = sLookup;
1014 *pca = ixCa;
1015
1016ErrExit:
1017 return hr;
1018} // RegMeta::_IsKnownCustomAttribute
1019
1020//*****************************************************************************
1021//*****************************************************************************
1022#ifdef _PREFAST_
1023#pragma warning(push)
1024#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1025#endif
1026HRESULT RegMeta::_HandleKnownCustomAttribute( // S_OK or error.
1027 mdToken tkObj, // [IN] Object being attributed.
1028 const void *pData, // [IN] Custom Attribute data blob.
1029 ULONG cbData, // [IN] Count of bytes in the data.
1030 int ixCa, // [IN] Value from KnownCustAttr enum.
1031 int *bKeep) // [OUT] If true, keep the CA after processing.
1032{
1033 HRESULT hr = S_OK; // A result.
1034 ULONG ixTbl; // Index of table with object.
1035 void *pRow; // Whatever sort of record it is.
1036 CMiniMdRW *pMiniMd = &m_pStgdb->m_MiniMd;
1037 mdToken tkObjType; // Type of the object.
1038 ULONG ix; // Loop control.
1039 KnownCaProp const *props=rKnownCaProps[ixCa]; // For convenience.
1040 CustomAttributeParser ca(pData, cbData);
1041 CQuickArray<CaArg> qArgs; // Un-named arguments.
1042 CQuickArray<CaNamedArg> qNamedArgs; // Named arguments.
1043 CQuickArray<BYTE> qNativeType;// Native type string.
1044
1045 _ASSERTE(ixCa > 0 && ixCa < CA_COUNT);
1046 *bKeep = props->bKeepCa || m_bKeepKnownCa;
1047
1048 // Validate that target is valid for attribute.
1049 tkObjType = TypeFromToken(tkObj);
1050 for (ix=0; props->rTypes[ix] != (mdToken) -1; ++ix)
1051 {
1052 if (props->rTypes[ix] == tkObjType)
1053 break;
1054 }
1055 // Was the type found in list of valid targets?
1056 if (props->rTypes[ix] == (mdToken) -1)
1057 { // No, error.
1058 IfFailGo(PostError(META_E_CA_INVALID_TARGET));
1059 }
1060 // Get the row.
1061 ixTbl = pMiniMd->GetTblForToken(tkObj);
1062 _ASSERTE(ixTbl >= 0 && ixTbl <= pMiniMd->GetCountTables());
1063 IfFailGo(pMiniMd->getRow(ixTbl, RidFromToken(tkObj), &pRow));
1064
1065 // If this custom attribute expects any args...
1066 if (props->cArgs || props->cNamedArgs)
1067 { // Initialize array ctor arg descriptors.
1068 IfFailGo(qArgs.ReSizeNoThrow(props->cArgs));
1069 for (ix=0; ix<props->cArgs; ++ix)
1070 qArgs[ix] = props->pArgs[ix];
1071 // Parse any ctor args (unnamed, fixed args).
1072 IfFailGo(ParseKnownCaArgs(ca, qArgs.Ptr(), props->cArgs));
1073
1074 // If this custom attribute accepts named args, parse them, or if there
1075 // are unused bytes, parse them.
1076 if (props->cNamedArgs || ca.BytesLeft() > 0)
1077 { // Initialize array of named arg descriptors.
1078 IfFailGo(qNamedArgs.ReSizeNoThrow(props->cNamedArgs));
1079 for (ix=0; ix<props->cNamedArgs; ++ix)
1080 qNamedArgs[ix] = props->pNamedArgs[ix];
1081 // Parse named args.
1082 IfFailGo(ParseKnownCaNamedArgs(ca, qNamedArgs.Ptr(), props->cNamedArgs));
1083 }
1084 }
1085
1086 switch (ixCa)
1087 {
1088 case CA_DllImportAttribute:
1089 {
1090 // Validate parameters.
1091 if (qArgs[0].val.str.cbStr == 0 || qArgs[0].val.str.pStr == NULL)
1092 {
1093 // no name for DllImport.
1094 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1095 }
1096
1097 // Retrieve / create a ModuleRef on the dll name.
1098 mdModuleRef mrModule;
1099 CQuickArray<char> qDllName;
1100 IfFailGo(qDllName.ReSizeNoThrow(qArgs[0].val.str.cbStr+1));
1101 memcpy(qDllName.Ptr(), qArgs[0].val.str.pStr, qArgs[0].val.str.cbStr);
1102 qDllName[qArgs[0].val.str.cbStr] = '\0';
1103 hr = ImportHelper::FindModuleRef(pMiniMd, qDllName.Ptr(), &mrModule);
1104 if (hr != S_OK)
1105 {
1106 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzDllName, qDllName.Ptr());
1107 if (wzDllName == NULL)
1108 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1109 IfFailGo(_DefineModuleRef(wzDllName, &mrModule));
1110 }
1111
1112 // Create a p/invoke map entry.
1113 ULONG dwFlags; dwFlags=0;
1114 // Was a calling convention set?
1115 if (qNamedArgs[DI_CallingConvention].val.type.tag)
1116 { // Calling convention makes no sense on a field.
1117 if (TypeFromToken(tkObj) == mdtFieldDef)
1118 IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_CallingConvention].szName));
1119 // Turn off all callconv bits, then turn on specified value.
1120 dwFlags &= ~pmCallConvMask;
1121 switch (qNamedArgs[DI_CallingConvention].val.u4)
1122 { //<TODO>@future: sigh. keep in sync with System.Runtime.InteropServices.CallingConvention</TODO>
1123 case 0: break; // 0 means "do nothing"
1124 case 1: dwFlags |= pmCallConvWinapi; break;
1125 case 2: dwFlags |= pmCallConvCdecl; break;
1126 case 3: dwFlags |= pmCallConvStdcall; break;
1127 case 4: dwFlags |= pmCallConvThiscall; break;
1128 case 5: dwFlags |= pmCallConvFastcall; break;
1129 default:
1130 _ASSERTE(!"Flags are out of sync! ");
1131 break;
1132 }
1133 }
1134 else
1135 if (TypeFromToken(tkObj) == mdtMethodDef)
1136 { // No calling convention specified for a method. Default to pmCallConvWinApi.
1137 dwFlags = (dwFlags & ~pmCallConvMask) | pmCallConvWinapi;
1138 }
1139
1140 // Charset
1141 if (qNamedArgs[DI_CharSet].val.type.tag)
1142 { // Turn of all charset bits, then turn on specified bits.
1143 dwFlags &= ~pmCharSetMask;
1144 switch (qNamedArgs[DI_CharSet].val.u4)
1145 { //<TODO>@future: keep in sync with System.Runtime.InteropServices.CharSet</TODO>
1146 case 0: break; // 0 means "do nothing"
1147 case 1: dwFlags |= pmCharSetNotSpec; break;
1148 case 2: dwFlags |= pmCharSetAnsi; break;
1149 case 3: dwFlags |= pmCharSetUnicode; break;
1150 case 4: dwFlags |= pmCharSetAuto; break;
1151 default:
1152 _ASSERTE(!"Flags are out of sync! ");
1153 break;
1154 }
1155 }
1156 if (qNamedArgs[DI_ExactSpelling].val.u1)
1157 dwFlags |= pmNoMangle;
1158 if (qNamedArgs[DI_SetLastError].val.type.tag)
1159 { // SetLastError makes no sense on a field.
1160 if (TypeFromToken(tkObj) == mdtFieldDef)
1161 IfFailGo(PostError(META_E_CA_INVALID_ARG_FOR_TYPE, qNamedArgs[DI_SetLastError].szName));
1162 if (qNamedArgs[DI_SetLastError].val.u1)
1163 dwFlags |= pmSupportsLastError;
1164 }
1165
1166 // If an entrypoint name was specified, use it, otherwise grab the name from the member.
1167 LPCWSTR wzEntry;
1168 if (qNamedArgs[DI_EntryPoint].val.type.tag)
1169 {
1170 if (qNamedArgs[DI_EntryPoint].val.str.cbStr > 0)
1171 {
1172 MAKE_WIDEPTR_FROMUTF8N_NOTHROW(wzEntryName, qNamedArgs[DI_EntryPoint].val.str.pStr, qNamedArgs[DI_EntryPoint].val.str.cbStr);
1173 if (wzEntryName == NULL)
1174 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1175 wzEntry = wzEntryName;
1176 }
1177 else
1178 wzEntry = W("");
1179 }
1180 else
1181 {
1182 LPCUTF8 szMember = NULL;
1183 if (TypeFromToken(tkObj) == mdtMethodDef)
1184 {
1185 IfFailGo(pMiniMd->getNameOfMethod(reinterpret_cast<MethodRec*>(pRow), &szMember));
1186 }
1187 MAKE_WIDEPTR_FROMUTF8_NOTHROW(wzMemberName, szMember);
1188 if (wzMemberName == NULL)
1189 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1190 wzEntry = wzMemberName;
1191 }
1192
1193 // Set the miPreserveSig bit based on the value of the preserve sig flag.
1194 if (qNamedArgs[DI_PreserveSig].val.type.tag && !qNamedArgs[DI_PreserveSig].val.u1)
1195 reinterpret_cast<MethodRec*>(pRow)->RemoveImplFlags(miPreserveSig);
1196 else
1197 reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
1198
1199 if (qNamedArgs[DI_BestFitMapping].val.type.tag)
1200 {
1201 if (qNamedArgs[DI_BestFitMapping].val.u1)
1202 dwFlags |= pmBestFitEnabled;
1203 else
1204 dwFlags |= pmBestFitDisabled;
1205 }
1206
1207 if (qNamedArgs[DI_ThrowOnUnmappableChar].val.type.tag)
1208 {
1209 if (qNamedArgs[DI_ThrowOnUnmappableChar].val.u1)
1210 dwFlags |= pmThrowOnUnmappableCharEnabled;
1211 else
1212 dwFlags |= pmThrowOnUnmappableCharDisabled;
1213 }
1214
1215 // Finally, create the PInvokeMap entry.,
1216 IfFailGo(_DefinePinvokeMap(tkObj, dwFlags, wzEntry, mrModule));
1217 goto ErrExit;
1218 }
1219 break;
1220
1221 case CA_GuidAttribute:
1222 { // Just verify the attribute. It still gets stored as a real custom attribute.
1223 // format is "{01234567-0123-0123-0123-001122334455}"
1224 GUID guid;
1225 WCHAR wzGuid[40];
1226 int cch = qArgs[0].val.str.cbStr;
1227
1228 // Guid should be 36 characters; need to add curlies.
1229 if (cch == 36)
1230 {
1231 WszMultiByteToWideChar(CP_UTF8, 0, qArgs[0].val.str.pStr,cch, wzGuid+1,39);
1232 wzGuid[0] = '{';
1233 wzGuid[37] = '}';
1234 wzGuid[38] = 0;
1235 hr = IIDFromString(wzGuid, &guid);
1236 }
1237 else
1238 hr = META_E_CA_INVALID_UUID;
1239 if (hr != S_OK)
1240 IfFailGo(PostError(META_E_CA_INVALID_UUID));
1241 goto ErrExit;
1242 }
1243 break;
1244
1245 case CA_ComImportAttribute:
1246 reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdImport);
1247 break;
1248
1249 case CA_InterfaceTypeAttribute:
1250 {
1251 // Verify the attribute.
1252 if (qArgs[0].val.u2 >= ifLast)
1253 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1254 }
1255 break;
1256
1257 case CA_ClassInterfaceAttribute:
1258 {
1259 // Verify the attribute.
1260 if (qArgs[0].val.u2 >= clsIfLast)
1261 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1262 }
1263 break;
1264
1265 case CA_SpecialNameAttribute:
1266
1267 switch (TypeFromToken(tkObj))
1268 {
1269 case mdtTypeDef:
1270 reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSpecialName);
1271 break;
1272
1273 case mdtMethodDef:
1274 reinterpret_cast<MethodRec*>(pRow)->AddFlags(mdSpecialName);
1275 break;
1276
1277 case mdtFieldDef:
1278 reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdSpecialName);
1279 break;
1280
1281 case mdtProperty:
1282 reinterpret_cast<PropertyRec*>(pRow)->AddPropFlags(prSpecialName);
1283 break;
1284
1285 case mdtEvent:
1286 reinterpret_cast<EventRec*>(pRow)->AddEventFlags(evSpecialName);
1287 break;
1288
1289 default:
1290 _ASSERTE(!"Unfamilar type for SpecialName custom attribute");
1291 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1292 }
1293
1294 break;
1295 case CA_SerializableAttribute:
1296 reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdSerializable);
1297 break;
1298
1299 case CA_NonSerializedAttribute:
1300 reinterpret_cast<FieldRec*>(pRow)->AddFlags(fdNotSerialized);
1301 break;
1302
1303 case CA_InAttribute:
1304 reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdIn);
1305 break;
1306
1307 case CA_OutAttribute:
1308 reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOut);
1309 break;
1310
1311 case CA_OptionalAttribute:
1312 reinterpret_cast<ParamRec*>(pRow)->AddFlags(pdOptional);
1313 break;
1314
1315 case CA_MethodImplAttribute2:
1316 // Force to wider value.
1317 qArgs[0].val.u4 = (unsigned)qArgs[0].val.i2;
1318 // Fall through to validation.
1319 case CA_MethodImplAttribute3:
1320 // Validate bits.
1321 if (qArgs[0].val.u4 & ~(miUserMask))
1322 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1323 reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(qArgs[0].val.u4);
1324 if (!qNamedArgs[MI_CodeType].val.type.tag)
1325 break;
1326 // fall through to set the code type.
1327 case CA_MethodImplAttribute1:
1328 {
1329 USHORT usFlags = reinterpret_cast<MethodRec*>(pRow)->GetImplFlags();
1330 if (qNamedArgs[MI_CodeType].val.i4 & ~(miCodeTypeMask))
1331 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1332 // Mask out old value, put in new one.
1333 usFlags = (usFlags & ~miCodeTypeMask) | qNamedArgs[MI_CodeType].val.i4;
1334 reinterpret_cast<MethodRec*>(pRow)->SetImplFlags(usFlags);
1335 }
1336 break;
1337
1338 case CA_MarshalAsAttribute1:
1339 // Force the U2 to a wider U4 value explicitly.
1340 qArgs[0].val.u4 = qArgs[0].val.u2;
1341 // Fall through to handle the CA.
1342 case CA_MarshalAsAttribute2:
1343 IfFailGo(_HandleNativeTypeCustomAttribute(tkObj, qArgs.Ptr(), qNamedArgs.Ptr(), qNativeType));
1344 break;
1345
1346 case CA_PreserveSigAttribute:
1347 reinterpret_cast<MethodRec*>(pRow)->AddImplFlags(miPreserveSig);
1348 break;
1349
1350 case CA_StructLayoutAttribute1:
1351 {
1352 // Convert the I2 to a U2, then wide to an I4, then fall through.
1353 qArgs[0].val.i4 = static_cast<int>(static_cast<USHORT>(qArgs[0].val.i2));
1354 }
1355 case CA_StructLayoutAttribute2:
1356 {
1357 // Get a copy of the flags to work with.
1358 ULONG dwFlags;
1359 dwFlags = reinterpret_cast<TypeDefRec*>(pRow)->GetFlags();
1360 // Class layout. Keep in sync with LayoutKind.
1361 switch (qArgs[0].val.i4)
1362 {
1363 case 0: // tdSequentialLayout:
1364 dwFlags = (dwFlags & ~tdLayoutMask) | tdSequentialLayout;
1365 break;
1366 case 2: // tdExplicitLayout:
1367 dwFlags = (dwFlags & ~tdLayoutMask) | tdExplicitLayout;
1368 break;
1369 case 3: // tdAutoLayout:
1370 dwFlags = (dwFlags & ~tdLayoutMask) | tdAutoLayout;
1371 break;
1372 default:
1373 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1374 break;
1375 }
1376
1377 // Class packing and size.
1378 ULONG ulSize, ulPack;
1379 ulPack = ulSize = ULONG_MAX;
1380 if (qNamedArgs[SL_Pack].val.type.tag)
1381 { // Only 1,2,4,8,16,32,64,128 are legal values.
1382 ulPack = qNamedArgs[SL_Pack].val.u4;
1383 if ((ulPack > 128) ||
1384 (ulPack & (ulPack-1)))
1385 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1386 }
1387 if (qNamedArgs[SL_Size].val.type.tag)
1388 {
1389 if (qNamedArgs[SL_Size].val.u4 > INT_MAX)
1390 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1391 ulSize = qNamedArgs[SL_Size].val.u4;
1392 }
1393 if (ulPack!=ULONG_MAX || ulSize!=ULONG_MAX)
1394 IfFailGo(_SetClassLayout(tkObj, ulPack, ulSize));
1395
1396 // Class character set.
1397 if (qNamedArgs[SL_CharSet].val.type.tag)
1398 {
1399 switch (qNamedArgs[SL_CharSet].val.u4)
1400 {
1401 //case 1: // Not specified.
1402 // IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1403 // break;
1404 case 2: // ANSI
1405 dwFlags = (dwFlags & ~tdStringFormatMask) | tdAnsiClass;
1406 break;
1407 case 3: // Unicode
1408 dwFlags = (dwFlags & ~tdStringFormatMask) | tdUnicodeClass;
1409 break;
1410 case 4: // Auto
1411 dwFlags = (dwFlags & ~tdStringFormatMask) | tdAutoClass;
1412 break;
1413 default:
1414 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1415 break;
1416 }
1417 }
1418
1419 // Persist possibly-changed value of flags.
1420 reinterpret_cast<TypeDefRec*>(pRow)->SetFlags(dwFlags);
1421 }
1422 break;
1423
1424 case CA_FieldOffsetAttribute:
1425 if (qArgs[0].val.u4 > INT_MAX)
1426 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1427 IfFailGo(_SetFieldOffset(tkObj, qArgs[0].val.u4));
1428 break;
1429
1430 case CA_TypeLibVersionAttribute:
1431 if ((qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0))
1432 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1433 break;
1434
1435 case CA_ComCompatibleVersionAttribute:
1436 if ( (qArgs[0].val.i4 < 0) || (qArgs[1].val.i4 < 0) || (qArgs[2].val.i4 < 0) || (qArgs[3].val.i4 < 0) )
1437 IfFailGo(PostError(META_E_CA_INVALID_VALUE));
1438 break;
1439
1440 case CA_AllowPartiallyTrustedCallersAttribute:
1441 break;
1442
1443 case CA_WindowsRuntimeImportAttribute:
1444 reinterpret_cast<TypeDefRec*>(pRow)->AddFlags(tdWindowsRuntime);
1445 break;
1446
1447 default:
1448 _ASSERTE(!"Unexpected custom attribute type");
1449 // Turn into ordinary custom attribute.
1450 *bKeep = true;
1451 hr = S_OK;
1452 goto ErrExit;
1453 break;
1454 }
1455
1456 IfFailGo(UpdateENCLog(tkObj));
1457
1458ErrExit:
1459 return hr;
1460} // RegMeta::_HandleKnownCustomAttribute
1461#ifdef _PREFAST_
1462#pragma warning(pop)
1463#endif
1464
1465//*****************************************************************************
1466//*****************************************************************************
1467#ifdef _PREFAST_
1468#pragma warning(push)
1469#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
1470#endif
1471HRESULT RegMeta::_HandleNativeTypeCustomAttribute(// S_OK or error.
1472 mdToken tkObj, // The token this CA is applied on.
1473 CaArg *pArgs, // Pointer to args.
1474 CaNamedArg *pNamedArgs, // Pointer to named args.
1475 CQuickArray<BYTE> &qNativeType) // Native type is built here.
1476{
1477 HRESULT hr = S_OK; // A result.
1478 int cch = 0; // Size of a string argument.
1479 ULONG cb; // Count of some character operation.
1480 ULONG cbNative; // Size of native type string.
1481 ULONG cbMax; // Max size of native type string.
1482 BYTE *pbNative; // Pointer into native type buffer.
1483 mdToken tkObjType; // The type of the token.
1484 mdToken tkSetter; // Token for Property setter.
1485 mdToken tkGetter; // Token for property getter.
1486 mdParamDef tkParam; // Parameter of getter/setter.
1487 ULONG cParams; // Count of params for getter/setter.
1488 HCORENUM phEnum = 0; // Enumerator for params.
1489 ULONG ulSeq; // Sequence of a param.
1490
1491 // Retrieve the type of the token.
1492 tkObjType = TypeFromToken(tkObj);
1493
1494 // Compute maximum size of the native type.
1495 if (pArgs[0].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
1496 { // N_T_* + 3 string lengths
1497 cbMax = sizeof(ULONG) * 4;
1498 // Marshal type - name of the type
1499 cbMax += pNamedArgs[M_MarshalType].val.str.cbStr;
1500 // Marshal type - type of the custom marshaler
1501 cbMax += pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
1502 // String cookie.
1503 cbMax += pNamedArgs[M_MarshalCookie].val.str.cbStr;
1504 }
1505 else if (pArgs[0].val.i4 == NATIVE_TYPE_SAFEARRAY)
1506 { // N_T_* + safe array sub-type + string length.
1507 cbMax = sizeof(ULONG) * 3;
1508 // Safe array record sub type.
1509 cbMax += pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
1510 }
1511 else
1512 { // N_T_* + sub-type + size + additive + NativeTypeArrayFlags.
1513 cbMax = sizeof(ULONG) * 4 + sizeof(UINT16);
1514 }
1515
1516 // IidParameterIndex.
1517 cbMax += sizeof(DWORD);
1518
1519 // Extra space to prevent buffer overrun.
1520 cbMax += 8;
1521
1522 // Size the array.
1523 IfFailGo(qNativeType.ReSizeNoThrow(cbMax));
1524 pbNative = qNativeType.Ptr();
1525 cbNative = 0;
1526
1527 //<TODO>@FUTURE: check for valid combinations of args.</TODO>
1528
1529 // Put in the NativeType.
1530 cb = CorSigCompressData(pArgs[0].val.i4, pbNative);
1531 if (cb == ((ULONG)(-1)))
1532 {
1533 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1534 }
1535
1536 cbNative += cb;
1537 pbNative += cb;
1538 if (cbNative > cbMax)
1539 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1540
1541 // Put in additional information, depending on native type.
1542 switch (pArgs[0].val.i4)
1543 {
1544 case NATIVE_TYPE_INTF:
1545 case NATIVE_TYPE_IUNKNOWN:
1546 case NATIVE_TYPE_IDISPATCH:
1547 // Validate that the IidParameterIndex field is valid if set.
1548 if (pNamedArgs[M_IidParameterIndex].val.type.tag)
1549 {
1550 int iidparam = pNamedArgs[M_IidParameterIndex].val.i4;
1551 if (iidparam < 0)
1552 IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
1553
1554 cb = CorSigCompressData(pNamedArgs[M_IidParameterIndex].val.i4, pbNative);
1555 if (cb == ((ULONG)(-1)))
1556 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1557
1558 cbNative += cb;
1559 pbNative += cb;
1560 if (cbNative > cbMax)
1561 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1562 }
1563 break;
1564
1565
1566 case NATIVE_TYPE_FIXEDARRAY:
1567 // Validate that only fields valid for NATIVE_TYPE_FIXEDARRAY are set.
1568 if (pNamedArgs[M_SafeArraySubType].val.type.tag)
1569 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1570
1571 if (pNamedArgs[M_SizeParamIndex].val.type.tag)
1572 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1573
1574 // This native type is only applicable on fields.
1575 if (tkObjType != mdtFieldDef)
1576 IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
1577
1578 if (pNamedArgs[M_SizeConst].val.type.tag)
1579 {
1580 // Make sure the size is not negative.
1581 if (pNamedArgs[M_SizeConst].val.i4 < 0)
1582 IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
1583
1584 cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
1585 if (cb == ((ULONG)(-1)))
1586 {
1587 IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
1588 }
1589
1590 }
1591 else
1592 {
1593 cb = CorSigCompressData(1, pbNative);
1594 if (cb == ((ULONG)(-1)))
1595 {
1596 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1597 }
1598 }
1599 cbNative += cb;
1600 pbNative += cb;
1601 if (cbNative > cbMax)
1602 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1603
1604 // Is there a sub type?
1605 if (pNamedArgs[M_ArraySubType].val.type.tag)
1606 {
1607 // Put in the sub type.
1608 cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
1609 if (cb == ((ULONG)(-1)))
1610 {
1611 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1612 }
1613 cbNative += cb;
1614 pbNative += cb;
1615 if (cbNative > cbMax)
1616 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1617 }
1618 break;
1619
1620 case NATIVE_TYPE_FIXEDSYSSTRING:
1621 // Validate that the required fields are set.
1622 if (!pNamedArgs[M_SizeConst].val.type.tag)
1623 IfFailGo(PostError(META_E_CA_FIXEDSTR_SIZE_REQUIRED));
1624
1625 // Validate that other array fields are not set.
1626 if (pNamedArgs[M_ArraySubType].val.type.tag)
1627 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1628 if (pNamedArgs[M_SizeParamIndex].val.type.tag)
1629 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1630 if (pNamedArgs[M_SafeArraySubType].val.type.tag)
1631 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1632
1633 // This native type is only applicable on fields.
1634 if (tkObjType != mdtFieldDef)
1635 IfFailGo(PostError(META_E_CA_NT_FIELDONLY));
1636
1637 // Put in the constant value.
1638 cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
1639 if (cb == ((ULONG)(-1)))
1640 {
1641 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1642 }
1643 cbNative += cb;
1644 pbNative += cb;
1645 if (cbNative > cbMax)
1646 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1647 break;
1648
1649 case NATIVE_TYPE_BYVALSTR:
1650 // This native type is only applicable on parameters.
1651 if (tkObjType != mdtParamDef)
1652 IfFailGo(PostError(META_E_CA_INVALID_TARGET));
1653 break;
1654
1655 case NATIVE_TYPE_SAFEARRAY:
1656 // Validate that other array fields are not set.
1657 if (pNamedArgs[M_ArraySubType].val.type.tag)
1658 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1659 if (pNamedArgs[M_SizeParamIndex].val.type.tag)
1660 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1661 if (pNamedArgs[M_SizeConst].val.type.tag)
1662 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1663
1664 // Is there a safe array sub type?
1665 if (pNamedArgs[M_SafeArraySubType].val.type.tag)
1666 {
1667 // Put in the safe array sub type.
1668 cb = CorSigCompressData(pNamedArgs[M_SafeArraySubType].val.i4, pbNative);
1669 if (cb == ((ULONG)(-1)))
1670 {
1671 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1672 }
1673 cbNative += cb;
1674 pbNative += cb;
1675 if (cbNative > cbMax)
1676 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1677
1678 // When the SAFEARRAY contains user defined types, the type of the
1679 // UDT can be specified in the SafeArrayUserDefinedSubType field.
1680 if (pNamedArgs[M_SafeArrayUserDefinedSubType].val.type.tag)
1681 {
1682 // Validate that this is only set for valid VT's.
1683 if (pNamedArgs[M_SafeArraySubType].val.i4 != VT_RECORD &&
1684 pNamedArgs[M_SafeArraySubType].val.i4 != VT_DISPATCH &&
1685 pNamedArgs[M_SafeArraySubType].val.i4 != VT_UNKNOWN)
1686 {
1687 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1688 }
1689
1690 // Encode the size of the string.
1691 cch = pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.cbStr;
1692 cb = CorSigCompressData(cch, pbNative);
1693 if (cb == ((ULONG)(-1)))
1694 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1695 cbNative += cb;
1696 pbNative += cb;
1697
1698 // Check that memcpy will fit and then encode the type name itself.
1699 if (ovadd_gt(cbNative, cch, cbMax))
1700 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1701 memcpy(pbNative, pNamedArgs[M_SafeArrayUserDefinedSubType].val.str.pStr, cch);
1702 cbNative += cch;
1703 pbNative += cch;
1704 _ASSERTE(cbNative <= cbMax);
1705 }
1706 }
1707 break;
1708
1709 case NATIVE_TYPE_ARRAY:
1710 // Validate that the array sub type is not set.
1711 if (pNamedArgs[M_SafeArraySubType].val.type.tag)
1712 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1713
1714 // Is there a sub type?
1715 if (pNamedArgs[M_ArraySubType].val.type.tag)
1716 {
1717 // Do some validation on the array sub type.
1718 if (pNamedArgs[M_ArraySubType].val.i4 == NATIVE_TYPE_CUSTOMMARSHALER)
1719 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1720
1721 // Put in the sub type.
1722 cb = CorSigCompressData(pNamedArgs[M_ArraySubType].val.i4, pbNative);
1723 if (cb == ((ULONG)(-1)))
1724 {
1725 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1726 }
1727 cbNative += cb;
1728 pbNative += cb;
1729 }
1730 else
1731 {
1732 // Put in the sub type.
1733 cb = CorSigCompressData(NATIVE_TYPE_MAX, pbNative);
1734 if (cb == ((ULONG)(-1)))
1735 {
1736 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1737 }
1738 cbNative += cb;
1739 pbNative += cb;
1740 }
1741 if (cbNative > cbMax)
1742 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1743
1744 // Is there a parameter index?
1745 if (pNamedArgs[M_SizeParamIndex].val.type.tag)
1746 {
1747 // Make sure the parameter index is not negative.
1748 if (pNamedArgs[M_SizeParamIndex].val.i4 < 0)
1749 IfFailGo(PostError(META_E_CA_NEGATIVE_PARAMINDEX));
1750
1751 // Yes, put it in.
1752 cb = CorSigCompressData(pNamedArgs[M_SizeParamIndex].val.i2, pbNative);
1753 if (cb == ((ULONG)(-1)))
1754 {
1755 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1756 }
1757 cbNative += cb;
1758 pbNative += cb;
1759 if (cbNative > cbMax)
1760 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1761
1762 // Is there a const?
1763 if (pNamedArgs[M_SizeConst].val.type.tag)
1764 {
1765 // Make sure the size is not negative.
1766 if (pNamedArgs[M_SizeConst].val.i4 < 0)
1767 IfFailGo(PostError(META_E_CA_NEGATIVE_CONSTSIZE));
1768
1769 // Yes, put it in.
1770 cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
1771 if (cb == ((ULONG)(-1)))
1772 {
1773 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1774 }
1775 cbNative += cb;
1776 pbNative += cb;
1777 if (cbNative > cbMax)
1778 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1779
1780 // Put in the flag indicating the size param index was specified.
1781 cb = CorSigCompressData((UINT16)ntaSizeParamIndexSpecified, pbNative);
1782 if (cb == ((ULONG)(-1)))
1783 {
1784 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1785 }
1786 cbNative += cb;
1787 pbNative += cb;
1788 if (cbNative > cbMax)
1789 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1790 }
1791 }
1792 else
1793 {
1794 // Is there a const?
1795 if (pNamedArgs[M_SizeConst].val.type.tag)
1796 {
1797 // Put in a param index of 0.
1798 cb = CorSigCompressData(0, pbNative);
1799 if (cb == ((ULONG)(-1)))
1800 {
1801 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1802 }
1803 cbNative += cb;
1804 pbNative += cb;
1805 if (cbNative > cbMax)
1806 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1807
1808 // Put in the constant value.
1809 cb = CorSigCompressData(pNamedArgs[M_SizeConst].val.i4, pbNative);
1810 if (cb == ((ULONG)(-1)))
1811 {
1812 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1813 }
1814 cbNative += cb;
1815 pbNative += cb;
1816 if (cbNative > cbMax)
1817 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1818
1819 // Set the flags field to 0 to indicate the size param index was not specified.
1820 cb = CorSigCompressData((UINT16)0, pbNative);
1821 if (cb == ((ULONG)(-1)))
1822 {
1823 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1824 }
1825 cbNative += cb;
1826 pbNative += cb;
1827 if (cbNative > cbMax)
1828 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1829 }
1830 }
1831 break;
1832
1833 case NATIVE_TYPE_CUSTOMMARSHALER:
1834 // Validate that the marshaler type field is set.
1835 if (!pNamedArgs[M_MarshalType].val.type.tag && !pNamedArgs[M_MarshalTypeRef].val.type.tag)
1836 IfFailGo(PostError(META_E_CA_CUSTMARSH_TYPE_REQUIRED));
1837
1838 // Put in the place holder for the unmanaged typelib guid.
1839 cb = CorSigCompressData(0, pbNative);
1840 if (cb == ((ULONG)(-1)))
1841 {
1842 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1843 }
1844 cbNative += cb;
1845 pbNative += cb;
1846 if (cbNative > cbMax)
1847 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1848
1849 // Put in the place holder for the unmanaged type name.
1850 cb = CorSigCompressData(0, pbNative);
1851 if (cb == ((ULONG)(-1)))
1852 {
1853 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1854 }
1855 cbNative += cb;
1856 pbNative += cb;
1857 if (cbNative > cbMax)
1858 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1859
1860 // Put in the marshaler type name.
1861 if (pNamedArgs[M_MarshalType].val.type.tag)
1862 {
1863 cch = pNamedArgs[M_MarshalType].val.str.cbStr;
1864 cb = CorSigCompressData(cch, pbNative);
1865 if (cb == ((ULONG)(-1)))
1866 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1867 cbNative += cb;
1868 pbNative += cb;
1869 // Check that memcpy will fit.
1870 if ((cbNative+cch) > cbMax)
1871 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1872 memcpy(pbNative, pNamedArgs[M_MarshalType].val.str.pStr, cch);
1873 cbNative += cch;
1874 pbNative += cch;
1875 _ASSERTE(cbNative <= cbMax);
1876 }
1877 else
1878 {
1879 cch = pNamedArgs[M_MarshalTypeRef].val.str.cbStr;
1880 cb = CorSigCompressData(cch, pbNative);
1881 if (cb == ((ULONG)(-1)))
1882 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1883 cbNative += cb;
1884 pbNative += cb;
1885 // Check that memcpy will fit.
1886 if ((cbNative+cch) > cbMax)
1887 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1888 memcpy(pbNative, pNamedArgs[M_MarshalTypeRef].val.str.pStr, cch);
1889 cbNative += cch;
1890 pbNative += cch;
1891 _ASSERTE(cbNative <= cbMax);
1892 }
1893
1894 // Put in the cookie.
1895 cch = pNamedArgs[M_MarshalCookie].val.str.cbStr;
1896 cb = CorSigCompressData(cch, pbNative);
1897 if (cb == ((ULONG)(-1)))
1898 {
1899 IfFailGo(PostError(META_E_CA_INVALID_BLOB));
1900 }
1901 cbNative += cb;
1902 pbNative += cb;
1903 // Check that memcpy will fit.
1904 if ((cbNative+cch) > cbMax)
1905 IfFailGo(PostError(META_E_CA_INVALID_MARSHALAS_FIELDS));
1906 memcpy(pbNative, pNamedArgs[M_MarshalCookie].val.str.pStr, cch);
1907 cbNative += cch;
1908 pbNative += cch;
1909 break;
1910 }
1911 _ASSERTE(cbNative <= cbMax);
1912
1913 // Resize to actual size.
1914 IfFailGo(qNativeType.ReSizeNoThrow(cbNative));
1915
1916 // Now apply the native type to actual token. If it is a property token,
1917 // apply to the methods.
1918 switch (TypeFromToken(tkObj))
1919 {
1920 case mdtParamDef:
1921 case mdtFieldDef:
1922 IfFailGo(_SetFieldMarshal(tkObj, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
1923 break;
1924
1925 case mdtProperty:
1926 // Get any setter/getter methods.
1927 IfFailGo(GetPropertyProps(tkObj, 0,0,0,0,0,0,0,0,0,0, &tkSetter, &tkGetter, 0,0,0));
1928 // For getter, put the field marshal on the return value.
1929 if (!IsNilToken(tkGetter))
1930 {
1931 // Search for first param.
1932 mdToken tk;
1933 tkParam = mdParamDefNil;
1934 do {
1935 IfFailGo(EnumParams(&phEnum, tkGetter, &tk, 1, &cParams));
1936 if (cParams > 0)
1937 {
1938 IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
1939 if (ulSeq == 0)
1940 {
1941 tkParam = tk;
1942 break;
1943 }
1944 }
1945
1946 } while (hr == S_OK);
1947 if (!IsNilToken(tkParam))
1948 IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
1949 CloseEnum(phEnum);
1950 phEnum = 0;
1951 }
1952 if (!IsNilToken(tkSetter))
1953 {
1954 // Determine the last param.
1955 PCCOR_SIGNATURE pSig;
1956 ULONG cbSig;
1957 mdToken tk;
1958 ULONG iSeq;
1959 IfFailGo(GetMethodProps(tkSetter, 0,0,0,0,0, &pSig,&cbSig, 0,0));
1960 tkParam = mdParamDefNil;
1961 CorSigUncompressData(pSig+1, &iSeq);
1962 // Search for last param.
1963 if (iSeq != 0)
1964 {
1965 do {
1966 IfFailGo(EnumParams(&phEnum, tkSetter, &tk, 1, &cParams));
1967 if (cParams > 0)
1968 {
1969 IfFailGo(GetParamProps(tk, 0, &ulSeq, 0,0,0,0,0,0,0));
1970 if (ulSeq == iSeq)
1971 {
1972 tkParam = tk;
1973 break;
1974 }
1975 }
1976 } while (hr == S_OK);
1977 }
1978 // If found one that is not return value
1979 if (!IsNilToken(tkParam))
1980 IfFailGo(_SetFieldMarshal(tkParam, (PCCOR_SIGNATURE)qNativeType.Ptr(), (DWORD)qNativeType.Size()));
1981 CloseEnum(phEnum);
1982 phEnum = 0;
1983 }
1984 break;
1985
1986 default:
1987 _ASSERTE(!"Should not have this token type in _HandleNativeTypeCustomAttribute()");
1988 break;
1989 }
1990
1991ErrExit:
1992 if (phEnum)
1993 CloseEnum(phEnum);
1994 return hr;
1995} // RegMeta::_HandleNativeTypeCustomAttribute
1996#ifdef _PREFAST_
1997#pragma warning(pop)
1998#endif
1999
2000#endif //FEATURE_METADATA_EMIT
2001