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.cpp - signature helpers. **
8 ** **
9 ****************************************************************************/
10#ifndef SOS_INCLUDE
11
12#ifdef _BLD_CLR
13#include "utilcode.h"
14#endif
15#include "corhlprpriv.h"
16#include <stdlib.h>
17
18/*************************************************************************************
19*
20* implementation of CQuickMemoryBase
21*
22*************************************************************************************/
23
24template <SIZE_T SIZE, SIZE_T INCREMENT>
25HRESULT CQuickMemoryBase<SIZE, INCREMENT>::ReSizeNoThrow(SIZE_T iItems)
26{
27#ifdef _BLD_CLR
28#ifdef _DEBUG
29#ifndef DACCESS_COMPILE
30 // Exercise heap for OOM-fault injection purposes
31 // But we can't do this if current thread suspends EE
32 if (!IsSuspendEEThread ())
33 {
34 BYTE *pTmp = NEW_NOTHROW(iItems);
35 if (!pTmp)
36 {
37 return E_OUTOFMEMORY;
38 }
39 delete [] pTmp;
40 }
41#endif
42#endif
43#endif
44 BYTE *pbBuffNew;
45 if (iItems <= cbTotal)
46 {
47 iSize = iItems;
48 return NOERROR;
49 }
50
51#ifdef _BLD_CLR
52#ifndef DACCESS_COMPILE
53 // not allowed to do allocation if current thread suspends EE
54 if (IsSuspendEEThread ())
55 return E_OUTOFMEMORY;
56#endif
57#endif
58 pbBuffNew = NEW_NOTHROW(iItems + INCREMENT);
59 if (!pbBuffNew)
60 return E_OUTOFMEMORY;
61 if (pbBuff)
62 {
63 memcpy(pbBuffNew, pbBuff, cbTotal);
64 delete [] pbBuff;
65 }
66 else
67 {
68 _ASSERTE(cbTotal == SIZE);
69 memcpy(pbBuffNew, rgData, cbTotal);
70 }
71 cbTotal = iItems + INCREMENT;
72 iSize = iItems;
73 pbBuff = pbBuffNew;
74 return NOERROR;
75}
76
77
78/*************************************************************************************
79*
80* get number of bytes consumed by one argument/return type
81*
82*************************************************************************************/
83#define CHECK_REMAINDER if(cbTotal >= cbTotalMax){hr=E_FAIL; goto ErrExit;}
84HRESULT _CountBytesOfOneArg(
85 PCCOR_SIGNATURE pbSig,
86 ULONG *pcbTotal) // Initially, *pcbTotal contains the remaining size of the sig blob
87{
88 ULONG cb;
89 ULONG cbTotal=0;
90 ULONG cbTotalMax;
91 CorElementType ulElementType;
92 ULONG ulData;
93 ULONG ulTemp;
94 int iData;
95 mdToken tk;
96 ULONG cArg;
97 ULONG callingconv;
98 ULONG cArgsIndex;
99 HRESULT hr = NOERROR;
100
101 if(pcbTotal==NULL) return E_FAIL;
102 cbTotalMax = *pcbTotal;
103
104 CHECK_REMAINDER;
105 cbTotal = CorSigUncompressElementType(pbSig, &ulElementType);
106 while (CorIsModifierElementType((CorElementType) ulElementType))
107 {
108 CHECK_REMAINDER;
109 cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType);
110 }
111 switch (ulElementType)
112 {
113 case ELEMENT_TYPE_SZARRAY:
114 case 0x1e /* obsolete */:
115 // skip over base type
116 CHECK_REMAINDER;
117 cb = cbTotalMax - cbTotal;
118 IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
119 cbTotal += cb;
120 break;
121
122 case ELEMENT_TYPE_FNPTR:
123 CHECK_REMAINDER;
124 cbTotal += CorSigUncompressData (&pbSig[cbTotal], &callingconv);
125
126 // remember number of bytes to represent the arg counts
127 CHECK_REMAINDER;
128 cbTotal += CorSigUncompressData (&pbSig[cbTotal], &cArg);
129
130 // how many bytes to represent the return type
131 CHECK_REMAINDER;
132 cb = cbTotalMax - cbTotal;
133 IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) );
134 cbTotal += cb;
135
136 // loop through argument
137 for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
138 {
139 CHECK_REMAINDER;
140 cb = cbTotalMax - cbTotal;
141 IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) );
142 cbTotal += cb;
143 }
144
145 break;
146
147 case ELEMENT_TYPE_ARRAY:
148 // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j]
149
150 // skip over base type
151 CHECK_REMAINDER;
152 cb = cbTotalMax - cbTotal;
153 IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
154 cbTotal += cb;
155
156 // Parse for the rank
157 CHECK_REMAINDER;
158 cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
159
160 // if rank == 0, we are done
161 if (ulData == 0)
162 break;
163
164 // any size of dimension specified?
165 CHECK_REMAINDER;
166 cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
167 while (ulData--)
168 {
169 CHECK_REMAINDER;
170 cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulTemp);
171 }
172
173 // any lower bound specified?
174 CHECK_REMAINDER;
175 cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData);
176
177 while (ulData--)
178 {
179 CHECK_REMAINDER;
180 cbTotal += CorSigUncompressSignedInt(&pbSig[cbTotal], &iData);
181 }
182
183 break;
184 case ELEMENT_TYPE_VALUETYPE:
185 case ELEMENT_TYPE_CLASS:
186 case ELEMENT_TYPE_CMOD_REQD:
187 case ELEMENT_TYPE_CMOD_OPT:
188 // count the bytes for the token compression
189 CHECK_REMAINDER;
190 cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk);
191 if ( ulElementType == ELEMENT_TYPE_CMOD_REQD ||
192 ulElementType == ELEMENT_TYPE_CMOD_OPT)
193 {
194 // skip over base type
195 CHECK_REMAINDER;
196 cb = cbTotalMax - cbTotal;
197 IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) );
198 cbTotal += cb;
199 }
200 break;
201 default:
202 break;
203 }
204
205 *pcbTotal = cbTotal;
206ErrExit:
207 return hr;
208}
209#undef CHECK_REMAINDER
210
211//*****************************************************************************
212// copy fixed part of VarArg signature to a buffer
213//*****************************************************************************
214HRESULT _GetFixedSigOfVarArg( // S_OK or error.
215 PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature
216 ULONG cbSigBlob, // [IN] size of signature
217 CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature
218 ULONG *pcbSigBlob) // [OUT] number of bytes written to the above output buffer
219{
220 HRESULT hr = NOERROR;
221 ULONG cbCalling;
222 ULONG cbTyArgsNumber = 0; // number of bytes to store the type arg count (generics only)
223 ULONG cbArgsNumber; // number of bytes to store the original arg count
224 ULONG cbArgsNumberTemp; // number of bytes to store the fixed arg count
225 ULONG cbTotal = 0; // total of number bytes for return type + all fixed arguments
226 ULONG cbCur = 0; // index through the pvSigBlob
227 ULONG cb;
228 ULONG cArg;
229 ULONG cTyArg;
230 ULONG callingconv;
231 ULONG cArgsIndex;
232 CorElementType ulElementType;
233 BYTE *pbSig;
234
235 _ASSERTE (pvSigBlob && pcbSigBlob);
236
237 // remember the number of bytes to represent the calling convention
238 cbCalling = CorSigUncompressData (pvSigBlob, &callingconv);
239 if (cbCalling == ((ULONG)(-1)))
240 {
241 return E_INVALIDARG;
242 }
243 _ASSERTE (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_VARARG));
244 cbCur += cbCalling;
245
246 if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC)
247 {
248 cbTyArgsNumber = CorSigUncompressData(&pvSigBlob[cbCur], &cTyArg);
249 if (cbTyArgsNumber == ((ULONG)(-1)))
250 {
251 return E_INVALIDARG;
252 }
253 cbCur += cbTyArgsNumber;
254 }
255
256 // remember number of bytes to represent the arg counts
257 cbArgsNumber= CorSigUncompressData (&pvSigBlob[cbCur], &cArg);
258 if (cbArgsNumber == ((ULONG)(-1)))
259 {
260 return E_INVALIDARG;
261 }
262
263 cbCur += cbArgsNumber;
264
265 // how many bytes to represent the return type
266 cb = cbSigBlob-cbCur;
267 IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) );
268 cbCur += cb;
269 cbTotal += cb;
270
271 // loop through argument until we found ELEMENT_TYPE_SENTINEL or run
272 // out of arguments
273 for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++)
274 {
275 _ASSERTE(cbCur < cbSigBlob);
276
277 // peak the outer most ELEMENT_TYPE_*
278 CorSigUncompressElementType (&pvSigBlob[cbCur], &ulElementType);
279 if (ulElementType == ELEMENT_TYPE_SENTINEL)
280 break;
281 cb = cbSigBlob-cbCur;
282 IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) );
283 cbTotal += cb;
284 cbCur += cb;
285 }
286
287 cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &cArg);
288
289 // now cbCalling : the number of bytes needed to store the calling convention
290 // cbArgNumberTemp : number of bytes to store the fixed arg count
291 // cbTotal : the number of bytes to store the ret and fixed arguments
292
293 *pcbSigBlob = cbCalling + cbArgsNumberTemp + cbTotal;
294
295 // resize the buffer
296 IfFailGo( pqbSig->ReSizeNoThrow(*pcbSigBlob) );
297 pbSig = (BYTE *)pqbSig->Ptr();
298
299 // copy over the calling convention
300 cb = CorSigCompressData(callingconv, pbSig);
301
302 // copy over the fixed arg count
303 cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &pbSig[cb]);
304
305 // copy over the fixed args + ret type
306 memcpy(&pbSig[cb + cbArgsNumberTemp], &pvSigBlob[cbCalling + cbArgsNumber], cbTotal);
307
308ErrExit:
309 return hr;
310}
311
312
313#endif // !SOS_INCLUDE
314