1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6//*****************************************************************************
7
8//
9// RegMeta.cpp
10//
11// Implementation for meta data public interface methods for full version.
12//
13//*****************************************************************************
14#include "stdafx.h"
15#include "regmeta.h"
16#include "metadata.h"
17#include "corerror.h"
18#include "mdutil.h"
19#include "rwutil.h"
20#include "mdlog.h"
21#include "importhelper.h"
22#include "filtermanager.h"
23#include "mdperf.h"
24#include "switches.h"
25#include "posterror.h"
26#include "stgio.h"
27#include "sstring.h"
28
29#include <metamodelrw.h>
30
31
32
33
34#define DEFINE_CUSTOM_NODUPCHECK 1
35#define DEFINE_CUSTOM_DUPCHECK 2
36#define SET_CUSTOM 3
37
38#if defined(_DEBUG) && defined(_TRACE_REMAPS)
39#define LOGGING
40#endif
41#include <log.h>
42
43#ifdef _MSC_VER
44#pragma warning(disable: 4102)
45#endif
46
47//*****************************************************************************
48// Call this after initialization is complete.
49//*****************************************************************************
50HRESULT RegMeta::AddToCache()
51{
52#if defined(FEATURE_METADATA_IN_VM)
53 HRESULT hr = S_OK;
54
55 // The ref count must be > 0 before the module is published, else another
56 // thread could find, use, and release the module, causing it to be deleted
57 // before this thread gets a chance to addref.
58 _ASSERTE(GetRefCount() > 0);
59 // add this RegMeta to the loaded module list.
60 m_bCached = true;
61 IfFailGo(LOADEDMODULES::AddModuleToLoadedList(this));
62ErrExit:
63 if (FAILED(hr))
64 {
65 _ASSERTE(!LOADEDMODULES::IsEntryInList(this));
66 m_bCached = false;
67 }
68 return hr;
69#else // FEATURE_METADATA_IN_VM
70 return S_OK;
71#endif // FEATURE_METADATA_IN_VM
72} // RegMeta::AddToCache
73
74
75//*****************************************************************************
76// Search the cached RegMetas for a given scope.
77//*****************************************************************************
78HRESULT RegMeta::FindCachedReadOnlyEntry(
79 LPCWSTR szName, // Name of the desired file.
80 DWORD dwOpenFlags, // Flags the new file is opened with.
81 RegMeta **ppMeta) // Put found RegMeta here.
82{
83#if defined(FEATURE_METADATA_IN_VM)
84 return LOADEDMODULES::FindCachedReadOnlyEntry(szName, dwOpenFlags, ppMeta);
85#else // FEATURE_METADATA_IN_VM
86 // No cache support in standalone version.
87 *ppMeta = NULL;
88 return S_FALSE;
89#endif // FEATURE_METADATA_IN_VM
90} // RegMeta::FindCachedReadOnlyEntry
91
92
93#ifdef FEATURE_METADATA_EMIT_ALL
94
95//*****************************************************************************
96// Helper function to startup the EE
97//
98// Notes:
99// This is called by code:RegMeta.DefineSecurityAttributeSet.
100//*****************************************************************************
101HRESULT RegMeta::StartupEE()
102{
103 UNREACHABLE_MSG_RET("About to CoCreateInstance! This code should not be "
104 "reachable or needs to be reimplemented for CoreCLR!");
105}
106
107#endif //FEATURE_METADATA_EMIT_ALL
108
109#ifdef FEATURE_METADATA_EMIT
110
111//*****************************************************************************
112// Persist a set of security custom attributes into a set of permission set
113// blobs on the same class or method.
114//
115// Notes:
116// Only in the full version because this is an emit operation.
117//*****************************************************************************
118HRESULT RegMeta::DefineSecurityAttributeSet(// Return code.
119 mdToken tkObj, // [IN] Class or method requiring security attributes.
120 COR_SECATTR rSecAttrs[], // [IN] Array of security attribute descriptions.
121 ULONG cSecAttrs, // [IN] Count of elements in above array.
122 ULONG *pulErrorAttr) // [OUT] On error, index of attribute causing problem.
123{
124 return E_NOTIMPL;
125} // RegMeta::DefineSecurityAttributeSet
126
127#endif //FEATURE_METADATA_EMIT
128
129
130//*****************************************************************************
131// Implementation of IMetaDataImport::ResolveTypeRef to resolve a typeref across scopes.
132//
133// Arguments:
134// tr - typeref within this scope to resolve
135// riid - interface on ppIScope to support
136// ppIScope - out-parameter to get metadata scope for typedef (*ptd)
137// ptd - out-parameter to get typedef that the ref resolves to.
138//
139// Notes:
140// TypeDefs define a type within a scope. TypeRefs refer to type-defs in other scopes
141// and allow you to import a type from another scope. This function attempts to determine
142// which type-def a type-ref points to.
143//
144// This resolve (type-ref, this cope) --> (type-def=*ptd, other scope=*ppIScope)
145//
146// However, this resolution requires knowing what modules have been loaded, which is not decided
147// until runtime via loader / fusion policy. Thus this interface can't possibly be correct since
148// it doesn't have that knowledge. Furthermore, when inspecting metadata from another process
149// (such as a debugger inspecting the debuggee's metadata), this API can be truly misleading.
150//
151// This API usage should be avoided.
152//
153//*****************************************************************************
154STDMETHODIMP
155RegMeta::ResolveTypeRef(
156 mdTypeRef tr,
157 REFIID riid,
158 IUnknown ** ppIScope,
159 mdTypeDef * ptd)
160{
161#ifdef FEATURE_METADATA_IN_VM
162 HRESULT hr;
163
164 BEGIN_ENTRYPOINT_NOTHROW;
165
166 TypeRefRec * pTypeRefRec;
167 WCHAR wzNameSpace[_MAX_PATH];
168 CMiniMdRW * pMiniMd = NULL;
169
170 LOG((LOGMD, "{%08x} RegMeta::ResolveTypeRef(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
171 this, tr, riid, ppIScope, ptd));
172
173 START_MD_PERF();
174 LOCKREAD();
175
176 pMiniMd = &(m_pStgdb->m_MiniMd);
177
178 _ASSERTE((ppIScope != NULL) && (ptd != NULL));
179
180 // Init the output values.
181 *ppIScope = NULL;
182 *ptd = 0;
183
184 if (IsNilToken(tr))
185 {
186 if (ptd != NULL)
187 {
188 *ptd = mdTypeDefNil;
189 }
190
191 if (ppIScope != NULL)
192 {
193 *ppIScope = NULL;
194 }
195
196 STOP_MD_PERF(ResolveTypeRef);
197 hr = E_INVALIDARG;
198 goto ErrExit;
199 }
200
201 if (TypeFromToken(tr) == mdtTypeDef)
202 {
203 // Shortcut when we receive a TypeDef token
204 *ptd = tr;
205 STOP_MD_PERF(ResolveTypeRef);
206 hr = this->QueryInterface(riid, (void **)ppIScope);
207 goto ErrExit;
208 }
209
210 // Get the class ref row.
211 _ASSERTE(TypeFromToken(tr) == mdtTypeRef);
212
213 IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tr), &pTypeRefRec));
214 IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, wzNameSpace, lengthof(wzNameSpace), NULL));
215 if (hr != NOERROR)
216 {
217 _ASSERTE(hr == CLDB_S_TRUNCATION);
218 // Truncate the namespace string
219 wzNameSpace[lengthof(wzNameSpace) - 1] = 0;
220 }
221
222 //***********************
223 // before we go off to CORPATH, check the loaded modules!
224 //***********************
225 if (LOADEDMODULES::ResolveTypeRefWithLoadedModules(
226 tr,
227 this,
228 pMiniMd,
229 riid,
230 ppIScope,
231 ptd) == NOERROR)
232 {
233 // Done!! We found one match among the loaded modules.
234 goto ErrExit;
235 }
236
237 IfFailGo(META_E_CANNOTRESOLVETYPEREF);
238
239ErrExit:
240 STOP_MD_PERF(ResolveTypeRef);
241 END_ENTRYPOINT_NOTHROW;
242
243 return hr;
244#else // FEATURE_METADATA_IN_VM
245 return E_NOTIMPL;
246#endif // FEATURE_METADATA_IN_VM
247} // RegMeta::ResolveTypeRef
248
249
250
251// Full version handles metadata caching, which Release() needs to coordinate with.
252// Thus Release() is in a satellite lib.
253ULONG RegMeta::Release()
254{
255 // This is called during cleanup. We can not fail this call by probing.
256 // As long as we make sure the cleanup does not use too much space through
257 // BEGIN_CLEANUP_ENTRYPOINT, we are OK.
258 CONTRACT_VIOLATION (SOToleranceViolation);
259 BEGIN_CLEANUP_ENTRYPOINT;
260
261#if defined(FEATURE_METADATA_IN_VM)
262 _ASSERTE(!m_bCached || LOADEDMODULES::IsEntryInList(this));
263#else
264 _ASSERTE(!m_bCached);
265#endif // FEATURE_METADATA_IN_VM
266 BOOL bCached = m_bCached;
267 ULONG cRef = InterlockedDecrement(&m_cRef);
268 // NOTE: 'this' may be unsafe after this point, if the module is cached, and
269 // another thread finds the module in the cache, releases it, and deletes it
270 // before we get around to deleting it. (That's why we must make a local copy
271 // of m_bCached.)
272 // If no references left...
273 if (cRef == 0)
274 {
275 if (!bCached)
276 { // If the module is not (was not) cached, no other thread can have
277 // discovered the module, so this thread can now safely delete it.
278 delete this;
279 }
280#if defined(FEATURE_METADATA_IN_VM)
281 else if (LOADEDMODULES::RemoveModuleFromLoadedList(this))
282 { // If the module was cached, RemoveModuleFromLoadedList() will try to
283 // safely un-publish the module, and if it succeeds, no other thread
284 // has (or will) discover the module, so this thread can delete it.
285 m_bCached = false;
286 delete this;
287 }
288#endif // FEATURE_METADATA_IN_VM
289 }
290 END_CLEANUP_ENTRYPOINT
291
292 return cRef;
293} // RegMeta::Release
294