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 | ** Corhlprpriv.h - ** |
8 | ** ** |
9 | *****************************************************************************/ |
10 | |
11 | #ifndef __CORHLPRPRIV_H__ |
12 | #define __CORHLPRPRIV_H__ |
13 | |
14 | #include "corhlpr.h" |
15 | #include "fstring.h" |
16 | |
17 | #if defined(_MSC_VER) && defined(_TARGET_X86_) |
18 | #pragma optimize("y", on) // If routines don't get inlined, don't pay the EBP frame penalty |
19 | #endif |
20 | |
21 | //***************************************************************************** |
22 | // |
23 | //***** Utility helpers |
24 | // |
25 | //***************************************************************************** |
26 | |
27 | #ifndef SOS_INCLUDE |
28 | |
29 | //***************************************************************************** |
30 | // |
31 | // **** CQuickBytes |
32 | // This helper class is useful for cases where 90% of the time you allocate 512 |
33 | // or less bytes for a data structure. This class contains a 512 byte buffer. |
34 | // Alloc() will return a pointer to this buffer if your allocation is small |
35 | // enough, otherwise it asks the heap for a larger buffer which is freed for |
36 | // you. No mutex locking is required for the small allocation case, making the |
37 | // code run faster, less heap fragmentation, etc... Each instance will allocate |
38 | // 520 bytes, so use accordinly. |
39 | // |
40 | //***************************************************************************** |
41 | namespace NSQuickBytesHelper |
42 | { |
43 | template <BOOL bThrow> |
44 | struct _AllocBytes; |
45 | |
46 | template <> |
47 | struct _AllocBytes<TRUE> |
48 | { |
49 | static BYTE *Invoke(SIZE_T iItems) |
50 | { |
51 | return NEW_THROWS(iItems); |
52 | } |
53 | }; |
54 | |
55 | template <> |
56 | struct _AllocBytes<FALSE> |
57 | { |
58 | static BYTE *Invoke(SIZE_T iItems) |
59 | { |
60 | return NEW_NOTHROW(iItems); |
61 | } |
62 | }; |
63 | }; |
64 | |
65 | void DECLSPEC_NORETURN ThrowHR(HRESULT hr); |
66 | |
67 | template <SIZE_T SIZE, SIZE_T INCREMENT> |
68 | class CQuickMemoryBase |
69 | { |
70 | protected: |
71 | template <typename ELEM_T> |
72 | static ELEM_T Min(ELEM_T a, ELEM_T b) |
73 | { return a < b ? a : b; } |
74 | |
75 | template <typename ELEM_T> |
76 | static ELEM_T Max(ELEM_T a, ELEM_T b) |
77 | { return a < b ? b : a; } |
78 | |
79 | // bGrow - indicates that this is a resize and that the original data |
80 | // needs to be copied over. |
81 | // bThrow - indicates whether or not memory allocations will throw. |
82 | template <BOOL bGrow, BOOL bThrow> |
83 | void *_Alloc(SIZE_T iItems) |
84 | { |
85 | #if defined(_BLD_CLR) && defined(_DEBUG) |
86 | { // Exercise heap for OOM-fault injection purposes |
87 | BYTE * pb = NSQuickBytesHelper::_AllocBytes<bThrow>::Invoke(iItems); |
88 | _ASSERTE(!bThrow || pb != NULL); // _AllocBytes would have thrown if bThrow == TRUE |
89 | if (pb == NULL) return NULL; // bThrow == FALSE and we failed to allocate memory |
90 | delete [] pb; // Success, delete allocated memory. |
91 | } |
92 | #endif |
93 | if (iItems <= cbTotal) |
94 | { // Fits within existing memory allocation |
95 | iSize = iItems; |
96 | } |
97 | else if (iItems <= SIZE) |
98 | { // Will fit in internal buffer. |
99 | if (pbBuff == NULL) |
100 | { // Any previous allocation is in the internal buffer and the new |
101 | // allocation fits in the internal buffer, so just update the size. |
102 | iSize = iItems; |
103 | cbTotal = SIZE; |
104 | } |
105 | else |
106 | { // There was a previous allocation, sitting in pbBuff |
107 | if (bGrow) |
108 | { // If growing, need to copy any existing data over. |
109 | memcpy(&rgData[0], pbBuff, Min(cbTotal, SIZE)); |
110 | } |
111 | |
112 | delete [] pbBuff; |
113 | pbBuff = NULL; |
114 | iSize = iItems; |
115 | cbTotal = SIZE; |
116 | } |
117 | } |
118 | else |
119 | { // Need to allocate a new buffer |
120 | SIZE_T cbTotalNew = iItems + (bGrow ? INCREMENT : 0); |
121 | BYTE * pbBuffNew = NSQuickBytesHelper::_AllocBytes<bThrow>::Invoke(cbTotalNew); |
122 | |
123 | if (!bThrow && pbBuffNew == NULL) |
124 | { // Allocation failed. Zero out structure. |
125 | if (pbBuff != NULL) |
126 | { // Delete old buffer |
127 | delete [] pbBuff; |
128 | } |
129 | pbBuff = NULL; |
130 | iSize = 0; |
131 | cbTotal = 0; |
132 | return NULL; |
133 | } |
134 | |
135 | if (bGrow && cbTotal > 0) |
136 | { // If growing, need to copy any existing data over. |
137 | memcpy(pbBuffNew, (BYTE *)Ptr(), Min(cbTotal, cbTotalNew)); |
138 | } |
139 | |
140 | if (pbBuff != NULL) |
141 | { // Delete old pre-existing buffer |
142 | delete [] pbBuff; |
143 | pbBuff = NULL; |
144 | } |
145 | |
146 | pbBuff = pbBuffNew; |
147 | cbTotal = cbTotalNew; |
148 | iSize = iItems; |
149 | } |
150 | |
151 | return Ptr(); |
152 | } |
153 | |
154 | public: |
155 | void Init() |
156 | { |
157 | pbBuff = 0; |
158 | iSize = 0; |
159 | cbTotal = SIZE; |
160 | } |
161 | |
162 | void Destroy() |
163 | { |
164 | if (pbBuff) |
165 | { |
166 | delete [] pbBuff; |
167 | pbBuff = 0; |
168 | } |
169 | } |
170 | |
171 | void *AllocThrows(SIZE_T iItems) |
172 | { |
173 | return _Alloc<FALSE /*bGrow*/, TRUE /*bThrow*/>(iItems); |
174 | } |
175 | |
176 | void *AllocNoThrow(SIZE_T iItems) |
177 | { |
178 | return _Alloc<FALSE /*bGrow*/, FALSE /*bThrow*/>(iItems); |
179 | } |
180 | |
181 | void ReSizeThrows(SIZE_T iItems) |
182 | { |
183 | _Alloc<TRUE /*bGrow*/, TRUE /*bThrow*/>(iItems); |
184 | } |
185 | |
186 | #ifdef __llvm__ |
187 | // This makes sure that we will not get an undefined symbol |
188 | // when building a release version of libcoreclr using LLVM. |
189 | __attribute__((used)) |
190 | #endif // __llvm__ |
191 | HRESULT ReSizeNoThrow(SIZE_T iItems); |
192 | |
193 | void Shrink(SIZE_T iItems) |
194 | { |
195 | _ASSERTE(iItems <= cbTotal); |
196 | iSize = iItems; |
197 | } |
198 | |
199 | operator PVOID() |
200 | { |
201 | return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]); |
202 | } |
203 | |
204 | void *Ptr() |
205 | { |
206 | return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]); |
207 | } |
208 | |
209 | const void *Ptr() const |
210 | { |
211 | return ((pbBuff) ? pbBuff : (PVOID)&rgData[0]); |
212 | } |
213 | |
214 | SIZE_T Size() const |
215 | { |
216 | return (iSize); |
217 | } |
218 | |
219 | SIZE_T MaxSize() const |
220 | { |
221 | return (cbTotal); |
222 | } |
223 | |
224 | void Maximize() |
225 | { |
226 | iSize = cbTotal; |
227 | } |
228 | |
229 | |
230 | // Convert UTF8 string to UNICODE string, optimized for speed |
231 | HRESULT ConvertUtf8_UnicodeNoThrow(const char * utf8str) |
232 | { |
233 | bool allAscii; |
234 | DWORD length; |
235 | |
236 | HRESULT hr = FString::Utf8_Unicode_Length(utf8str, & allAscii, & length); |
237 | |
238 | if (SUCCEEDED(hr)) |
239 | { |
240 | LPWSTR buffer = (LPWSTR) AllocNoThrow((length + 1) * sizeof(WCHAR)); |
241 | |
242 | if (buffer == NULL) |
243 | { |
244 | hr = E_OUTOFMEMORY; |
245 | } |
246 | else |
247 | { |
248 | hr = FString::Utf8_Unicode(utf8str, allAscii, buffer, length); |
249 | } |
250 | } |
251 | |
252 | return hr; |
253 | } |
254 | |
255 | // Convert UTF8 string to UNICODE string, optimized for speed |
256 | void ConvertUtf8_Unicode(const char * utf8str) |
257 | { |
258 | bool allAscii; |
259 | DWORD length; |
260 | |
261 | HRESULT hr = FString::Utf8_Unicode_Length(utf8str, & allAscii, & length); |
262 | |
263 | if (SUCCEEDED(hr)) |
264 | { |
265 | LPWSTR buffer = (LPWSTR) AllocThrows((length + 1) * sizeof(WCHAR)); |
266 | |
267 | hr = FString::Utf8_Unicode(utf8str, allAscii, buffer, length); |
268 | } |
269 | |
270 | if (FAILED(hr)) |
271 | { |
272 | ThrowHR(hr); |
273 | } |
274 | } |
275 | |
276 | // Convert UNICODE string to UTF8 string, optimized for speed |
277 | void ConvertUnicode_Utf8(const WCHAR * pString) |
278 | { |
279 | bool allAscii; |
280 | DWORD length; |
281 | |
282 | HRESULT hr = FString::Unicode_Utf8_Length(pString, & allAscii, & length); |
283 | |
284 | if (SUCCEEDED(hr)) |
285 | { |
286 | LPSTR buffer = (LPSTR) AllocThrows((length + 1) * sizeof(char)); |
287 | |
288 | hr = FString::Unicode_Utf8(pString, allAscii, buffer, length); |
289 | } |
290 | |
291 | if (FAILED(hr)) |
292 | { |
293 | ThrowHR(hr); |
294 | } |
295 | } |
296 | |
297 | // Copy single byte string and hold it |
298 | const char * SetStringNoThrow(const char * pStr, SIZE_T len) |
299 | { |
300 | LPSTR buffer = (LPSTR) AllocNoThrow(len + 1); |
301 | |
302 | if (buffer != NULL) |
303 | { |
304 | memcpy(buffer, pStr, len); |
305 | buffer[len] = 0; |
306 | } |
307 | |
308 | return buffer; |
309 | } |
310 | |
311 | #ifdef DACCESS_COMPILE |
312 | void |
313 | EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
314 | { |
315 | // Assume that 'this' is enumerated, either explicitly |
316 | // or because this class is embedded in another. |
317 | DacEnumMemoryRegion(dac_cast<TADDR>(pbBuff), iSize); |
318 | } |
319 | #endif // DACCESS_COMPILE |
320 | |
321 | BYTE *pbBuff; |
322 | SIZE_T iSize; // number of bytes used |
323 | SIZE_T cbTotal; // total bytes allocated in the buffer |
324 | // use UINT64 to enforce the alignment of the memory |
325 | UINT64 rgData[(SIZE+sizeof(UINT64)-1)/sizeof(UINT64)]; |
326 | }; |
327 | |
328 | // These should be multiples of 8 so that data can be naturally aligned. |
329 | #define CQUICKBYTES_BASE_SIZE 512 |
330 | #define CQUICKBYTES_INCREMENTAL_SIZE 128 |
331 | |
332 | class CQuickBytesBase : public CQuickMemoryBase<CQUICKBYTES_BASE_SIZE, CQUICKBYTES_INCREMENTAL_SIZE> |
333 | { |
334 | }; |
335 | |
336 | |
337 | class CQuickBytes : public CQuickBytesBase |
338 | { |
339 | public: |
340 | CQuickBytes() |
341 | { |
342 | Init(); |
343 | } |
344 | |
345 | ~CQuickBytes() |
346 | { |
347 | Destroy(); |
348 | } |
349 | }; |
350 | |
351 | /* to be used as static variable - no constructor/destructor, assumes zero |
352 | initialized memory */ |
353 | class CQuickBytesStatic : public CQuickBytesBase |
354 | { |
355 | }; |
356 | |
357 | template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE> |
358 | class CQuickBytesSpecifySizeBase : public CQuickMemoryBase<CQUICKBYTES_BASE_SPECIFY_SIZE, CQUICKBYTES_INCREMENTAL_SIZE> |
359 | { |
360 | }; |
361 | |
362 | template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE> |
363 | class CQuickBytesSpecifySize : public CQuickBytesSpecifySizeBase<CQUICKBYTES_BASE_SPECIFY_SIZE> |
364 | { |
365 | public: |
366 | CQuickBytesSpecifySize() |
367 | { |
368 | this->Init(); |
369 | } |
370 | |
371 | ~CQuickBytesSpecifySize() |
372 | { |
373 | this->Destroy(); |
374 | } |
375 | }; |
376 | |
377 | /* to be used as static variable - no constructor/destructor, assumes zero |
378 | initialized memory */ |
379 | template <SIZE_T CQUICKBYTES_BASE_SPECIFY_SIZE> |
380 | class CQuickBytesSpecifySizeStatic : public CQuickBytesSpecifySizeBase<CQUICKBYTES_BASE_SPECIFY_SIZE> |
381 | { |
382 | }; |
383 | |
384 | template <class T> class CQuickArrayBase : public CQuickBytesBase |
385 | { |
386 | public: |
387 | T* AllocThrows(SIZE_T iItems) |
388 | { |
389 | CheckOverflowThrows(iItems); |
390 | return (T*)CQuickBytesBase::AllocThrows(iItems * sizeof(T)); |
391 | } |
392 | |
393 | void ReSizeThrows(SIZE_T iItems) |
394 | { |
395 | CheckOverflowThrows(iItems); |
396 | CQuickBytesBase::ReSizeThrows(iItems * sizeof(T)); |
397 | } |
398 | |
399 | T* AllocNoThrow(SIZE_T iItems) |
400 | { |
401 | if (!CheckOverflowNoThrow(iItems)) |
402 | { |
403 | return NULL; |
404 | } |
405 | return (T*)CQuickBytesBase::AllocNoThrow(iItems * sizeof(T)); |
406 | } |
407 | |
408 | HRESULT ReSizeNoThrow(SIZE_T iItems) |
409 | { |
410 | if (!CheckOverflowNoThrow(iItems)) |
411 | { |
412 | return E_OUTOFMEMORY; |
413 | } |
414 | return CQuickBytesBase::ReSizeNoThrow(iItems * sizeof(T)); |
415 | } |
416 | |
417 | void Shrink(SIZE_T iItems) |
418 | { |
419 | CQuickBytesBase::Shrink(iItems * sizeof(T)); |
420 | } |
421 | |
422 | T* Ptr() |
423 | { |
424 | return (T*) CQuickBytesBase::Ptr(); |
425 | } |
426 | |
427 | const T* Ptr() const |
428 | { |
429 | return (T*) CQuickBytesBase::Ptr(); |
430 | } |
431 | |
432 | SIZE_T Size() const |
433 | { |
434 | return CQuickBytesBase::Size() / sizeof(T); |
435 | } |
436 | |
437 | SIZE_T MaxSize() const |
438 | { |
439 | return CQuickBytesBase::cbTotal / sizeof(T); |
440 | } |
441 | |
442 | T& operator[] (SIZE_T ix) |
443 | { |
444 | _ASSERTE(ix < Size()); |
445 | return *(Ptr() + ix); |
446 | } |
447 | |
448 | const T& operator[] (SIZE_T ix) const |
449 | { |
450 | _ASSERTE(ix < Size()); |
451 | return *(Ptr() + ix); |
452 | } |
453 | |
454 | private: |
455 | inline |
456 | BOOL CheckOverflowNoThrow(SIZE_T iItems) |
457 | { |
458 | SIZE_T totalSize = iItems * sizeof(T); |
459 | |
460 | if (totalSize / sizeof(T) != iItems) |
461 | { |
462 | return FALSE; |
463 | } |
464 | |
465 | return TRUE; |
466 | } |
467 | |
468 | inline |
469 | void CheckOverflowThrows(SIZE_T iItems) |
470 | { |
471 | if (!CheckOverflowNoThrow(iItems)) |
472 | { |
473 | THROW_OUT_OF_MEMORY(); |
474 | } |
475 | } |
476 | }; |
477 | |
478 | template <class T> class CQuickArray : public CQuickArrayBase<T> |
479 | { |
480 | public: |
481 | CQuickArray<T>() |
482 | { |
483 | this->Init(); |
484 | } |
485 | |
486 | ~CQuickArray<T>() |
487 | { |
488 | this->Destroy(); |
489 | } |
490 | }; |
491 | |
492 | // This is actually more of a stack with array access. Essentially, you can |
493 | // only add elements through Push and remove them through Pop, but you can |
494 | // access and modify any random element with the index operator. You cannot |
495 | // access elements that have not been added. |
496 | |
497 | template <class T> |
498 | class CQuickArrayList : protected CQuickArray<T> |
499 | { |
500 | private: |
501 | SIZE_T m_curSize; |
502 | |
503 | public: |
504 | // Make these specific functions public. |
505 | using CQuickArray<T>::AllocThrows; |
506 | using CQuickArray<T>::ReSizeThrows; |
507 | using CQuickArray<T>::AllocNoThrow; |
508 | using CQuickArray<T>::ReSizeNoThrow; |
509 | using CQuickArray<T>::MaxSize; |
510 | |
511 | CQuickArrayList() |
512 | : m_curSize(0) |
513 | { |
514 | this->Init(); |
515 | } |
516 | |
517 | ~CQuickArrayList() |
518 | { |
519 | this->Destroy(); |
520 | } |
521 | |
522 | // Can only access values that have been pushed. |
523 | T& operator[] (SIZE_T ix) |
524 | { |
525 | _ASSERTE(ix < m_curSize); |
526 | return CQuickArray<T>::operator[](ix); |
527 | } |
528 | |
529 | // Can only access values that have been pushed. |
530 | const T& operator[] (SIZE_T ix) const |
531 | { |
532 | _ASSERTE(ix < m_curSize); |
533 | return CQuickArray<T>::operator[](ix); |
534 | } |
535 | |
536 | // THROWS: Resizes if necessary. |
537 | void Push(const T & value) |
538 | { |
539 | // Resize if necessary - thows. |
540 | if (m_curSize + 1 >= CQuickArray<T>::Size()) |
541 | ReSizeThrows((m_curSize + 1) * 2); |
542 | |
543 | // Append element to end of array. |
544 | _ASSERTE(m_curSize + 1 < CQuickArray<T>::Size()); |
545 | SIZE_T ix = m_curSize++; |
546 | (*this)[ix] = value; |
547 | } |
548 | |
549 | T Pop() |
550 | { |
551 | _ASSERTE(m_curSize > 0); |
552 | T retval = (*this)[m_curSize - 1]; |
553 | INDEBUG(ZeroMemory(&(this->Ptr()[m_curSize - 1]), sizeof(T));) |
554 | --m_curSize; |
555 | return retval; |
556 | } |
557 | |
558 | SIZE_T Size() const |
559 | { |
560 | return m_curSize; |
561 | } |
562 | |
563 | void Shrink() |
564 | { |
565 | CQuickArray<T>::Shrink(m_curSize); |
566 | } |
567 | }; |
568 | |
569 | |
570 | /* to be used as static variable - no constructor/destructor, assumes zero |
571 | initialized memory */ |
572 | template <class T> class CQuickArrayStatic : public CQuickArrayBase<T> |
573 | { |
574 | }; |
575 | |
576 | typedef CQuickArrayBase<WCHAR> CQuickWSTRBase; |
577 | typedef CQuickArray<WCHAR> CQuickWSTR; |
578 | typedef CQuickArrayStatic<WCHAR> CQuickWSTRStatic; |
579 | |
580 | typedef CQuickArrayBase<CHAR> CQuickSTRBase; |
581 | typedef CQuickArray<CHAR> CQuickSTR; |
582 | typedef CQuickArrayStatic<CHAR> CQuickSTRStatic; |
583 | |
584 | class RidBitmap |
585 | { |
586 | public: |
587 | HRESULT InsertToken(mdToken token) |
588 | { |
589 | HRESULT hr = S_OK; |
590 | mdToken rid = RidFromToken(token); |
591 | SIZE_T index = rid / 8; |
592 | BYTE bit = (1 << (rid % 8)); |
593 | |
594 | if (index >= buffer.Size()) |
595 | { |
596 | SIZE_T oldSize = buffer.Size(); |
597 | SIZE_T newSize = index+1+oldSize/8; |
598 | IfFailRet(buffer.ReSizeNoThrow(newSize)); |
599 | memset(&buffer[oldSize], 0, newSize-oldSize); |
600 | } |
601 | |
602 | buffer[index] |= bit; |
603 | return hr; |
604 | } |
605 | |
606 | bool IsTokenInBitmap(mdToken token) |
607 | { |
608 | mdToken rid = RidFromToken(token); |
609 | SIZE_T index = rid / 8; |
610 | BYTE bit = (1 << (rid % 8)); |
611 | |
612 | return ((index < buffer.Size()) && (buffer[index] & bit)); |
613 | } |
614 | |
615 | void Reset() |
616 | { |
617 | if (buffer.Size()) |
618 | { |
619 | memset(&buffer[0], 0, buffer.Size()); |
620 | } |
621 | } |
622 | |
623 | private: |
624 | CQuickArray<BYTE> buffer; |
625 | }; |
626 | |
627 | //***************************************************************************** |
628 | // |
629 | //***** Signature helpers |
630 | // |
631 | //***************************************************************************** |
632 | |
633 | HRESULT _CountBytesOfOneArg( |
634 | PCCOR_SIGNATURE pbSig, |
635 | ULONG *pcbTotal); |
636 | |
637 | HRESULT _GetFixedSigOfVarArg( // S_OK or error. |
638 | PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of CLR signature |
639 | ULONG cbSigBlob, // [IN] size of signature |
640 | CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature |
641 | ULONG *pcbSigBlob); // [OUT] number of bytes written to the above output buffer |
642 | |
643 | #endif //!SOS_INCLUDE |
644 | |
645 | #if defined(_MSC_VER) && defined(_TARGET_X86_) |
646 | #pragma optimize("", on) // restore command line default optimizations |
647 | #endif |
648 | |
649 | |
650 | //--------------------------------------------------------------------------------------- |
651 | // |
652 | // Reads compressed integer from buffer pData, fills the result to *pnDataOut. Advances buffer pointer. |
653 | // Doesn't read behind the end of the buffer (the end starts at pDataEnd). |
654 | // |
655 | inline |
656 | __checkReturn |
657 | HRESULT |
658 | CorSigUncompressData_EndPtr( |
659 | PCCOR_SIGNATURE & pData, // [IN,OUT] Buffer |
660 | PCCOR_SIGNATURE pDataEnd, // End of buffer |
661 | DWORD * pnDataOut) // [OUT] Compressed integer read from the buffer |
662 | { |
663 | _ASSERTE(pData <= pDataEnd); |
664 | HRESULT hr = S_OK; |
665 | |
666 | INT_PTR cbDataSize = pDataEnd - pData; |
667 | if (cbDataSize > 4) |
668 | { // Compressed integer cannot be bigger than 4 bytes |
669 | cbDataSize = 4; |
670 | } |
671 | DWORD dwDataSize = (DWORD)cbDataSize; |
672 | |
673 | ULONG cbDataOutLength; |
674 | IfFailRet(CorSigUncompressData( |
675 | pData, |
676 | dwDataSize, |
677 | pnDataOut, |
678 | &cbDataOutLength)); |
679 | pData += cbDataOutLength; |
680 | |
681 | return hr; |
682 | } // CorSigUncompressData_EndPtr |
683 | |
684 | //--------------------------------------------------------------------------------------- |
685 | // |
686 | // Reads CorElementType (1 byte) from buffer pData, fills the result to *pTypeOut. Advances buffer pointer. |
687 | // Doesn't read behind the end of the buffer (the end starts at pDataEnd). |
688 | // |
689 | inline |
690 | __checkReturn |
691 | HRESULT |
692 | CorSigUncompressElementType_EndPtr( |
693 | PCCOR_SIGNATURE & pData, // [IN,OUT] Buffer |
694 | PCCOR_SIGNATURE pDataEnd, // End of buffer |
695 | CorElementType * pTypeOut) // [OUT] ELEMENT_TYPE_* value read from the buffer |
696 | { |
697 | _ASSERTE(pData <= pDataEnd); |
698 | // We don't expect pData > pDataEnd, but the runtime check doesn't cost much and it is more secure in |
699 | // case caller has a bug |
700 | if (pData >= pDataEnd) |
701 | { // No data |
702 | return META_E_BAD_SIGNATURE; |
703 | } |
704 | // Read 'type' as 1 byte |
705 | *pTypeOut = (CorElementType)*pData; |
706 | pData++; |
707 | |
708 | return S_OK; |
709 | } // CorSigUncompressElementType_EndPtr |
710 | |
711 | //--------------------------------------------------------------------------------------- |
712 | // |
713 | // Reads pointer (4/8 bytes) from buffer pData, fills the result to *ppvPointerOut. Advances buffer pointer. |
714 | // Doesn't read behind the end of the buffer (the end starts at pDataEnd). |
715 | // |
716 | inline |
717 | __checkReturn |
718 | HRESULT |
719 | CorSigUncompressPointer_EndPtr( |
720 | PCCOR_SIGNATURE & pData, // [IN,OUT] Buffer |
721 | PCCOR_SIGNATURE pDataEnd, // End of buffer |
722 | void ** ppvPointerOut) // [OUT] Pointer value read from the buffer |
723 | { |
724 | _ASSERTE(pData <= pDataEnd); |
725 | // We could just skip this check as pointers should be only in trusted (and therefore correct) |
726 | // signatures and we check for that on the caller side, but it won't hurt to have this check and it will |
727 | // make it easier to catch invalid signatures in trusted code (e.g. IL stubs, NGEN images, etc.) |
728 | if (pData + sizeof(void *) > pDataEnd) |
729 | { // Not enough data in the buffer |
730 | _ASSERTE(!"This signature is invalid. Note that caller should check that it is not comming from untrusted source!" ); |
731 | return META_E_BAD_SIGNATURE; |
732 | } |
733 | *ppvPointerOut = *(void * UNALIGNED *)pData; |
734 | pData += sizeof(void *); |
735 | |
736 | return S_OK; |
737 | } // CorSigUncompressPointer_EndPtr |
738 | |
739 | //--------------------------------------------------------------------------------------- |
740 | // |
741 | // Reads compressed TypeDef/TypeRef/TypeSpec token, fills the result to *pnDataOut. Advances buffer pointer. |
742 | // Doesn't read behind the end of the buffer (the end starts at pDataEnd). |
743 | // |
744 | inline |
745 | __checkReturn |
746 | HRESULT |
747 | CorSigUncompressToken_EndPtr( |
748 | PCCOR_SIGNATURE & pData, // [IN,OUT] Buffer |
749 | PCCOR_SIGNATURE pDataEnd, // End of buffer |
750 | mdToken * ptkTokenOut) // [OUT] Token read from the buffer |
751 | { |
752 | _ASSERTE(pData <= pDataEnd); |
753 | HRESULT hr = S_OK; |
754 | |
755 | INT_PTR cbDataSize = pDataEnd - pData; |
756 | if (cbDataSize > 4) |
757 | { // Compressed token cannot be bigger than 4 bytes |
758 | cbDataSize = 4; |
759 | } |
760 | DWORD dwDataSize = (DWORD)cbDataSize; |
761 | |
762 | ULONG cbTokenOutLength; |
763 | IfFailRet(CorSigUncompressToken( |
764 | pData, |
765 | dwDataSize, |
766 | ptkTokenOut, |
767 | &cbTokenOutLength)); |
768 | pData += cbTokenOutLength; |
769 | |
770 | return hr; |
771 | } // CorSigUncompressToken_EndPtr |
772 | |
773 | #endif // __CORHLPRPRIV_H__ |
774 | |