Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

719 lines
20 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name :
  4. fullptr.c
  5. Abstract :
  6. This file contains the APIs for handling full pointers in the NDR engine
  7. and inlined stubs for MIDL 2.0.
  8. Author :
  9. David Kays dkays January 1994.
  10. Revision History :
  11. ---------------------------------------------------------------------*/
  12. #include "ndrp.h"
  13. static void
  14. NdrFullPointerXlatRealloc ( PFULL_PTR_XLAT_TABLES pXlatTables, ulong RefId );
  15. PFULL_PTR_XLAT_TABLES RPC_ENTRY
  16. NdrFullPointerXlatInit(
  17. ulong NumberOfPointers,
  18. XLAT_SIDE XlatSide )
  19. /***
  20. Routine description :
  21. Allocates full pointer support data structures for an RPC call.
  22. Arguments :
  23. NumberOfPointer - If possible, the stub passes in the total number
  24. of possible full pointers that will be used during a call.
  25. Return value :
  26. A pointer to the full pointer translations tables used during an rpc call.
  27. ***/
  28. {
  29. PFULL_PTR_XLAT_TABLES pXlatTables;
  30. uint RefIdToPointerEntries;
  31. uint PointerToRefIdBuckets;
  32. BOOL fOutOfMemory = FALSE;
  33. pXlatTables = (PFULL_PTR_XLAT_TABLES)
  34. I_RpcAllocate(sizeof(FULL_PTR_XLAT_TABLES));
  35. // Because old compilers didn't initialize the xlat ptr in stubmsg
  36. // at the client in Os mode, we cannot raise exception right away.
  37. if ( ! pXlatTables )
  38. fOutOfMemory = TRUE;
  39. else
  40. {
  41. //
  42. // Determine the size of both translation tables.
  43. //
  44. if ( NumberOfPointers )
  45. {
  46. ulong Shift, Bitmask;
  47. RefIdToPointerEntries = (uint) NumberOfPointers;
  48. //
  49. // Find the smallest power of 2 which is greater than
  50. // RefIdToPointerEntries.
  51. //
  52. for ( Shift = 0, Bitmask = 0x80000000;
  53. ! (Bitmask & (ulong) RefIdToPointerEntries);
  54. Shift++, Bitmask >>= 1 )
  55. ;
  56. PointerToRefIdBuckets = (uint)((0xffffffff >> Shift) + 1);
  57. }
  58. else
  59. {
  60. RefIdToPointerEntries = DEFAULT_REF_ID_TO_POINTER_TABLE_ELEMENTS;
  61. PointerToRefIdBuckets = DEFAULT_POINTER_TO_REF_ID_TABLE_BUCKETS;
  62. }
  63. // Make sure we can clean up correctly later if case of an exception.
  64. pXlatTables->RefIdToPointer.XlatTable = 0;
  65. pXlatTables->RefIdToPointer.StateTable = 0;
  66. pXlatTables->PointerToRefId.XlatTable = 0;
  67. pXlatTables->RefIdToPointer.NumberOfEntries = 0;
  68. pXlatTables->PointerToRefId.NumberOfBuckets = 0;
  69. //
  70. // Initialize the ref id to pointer tables.
  71. //
  72. pXlatTables->RefIdToPointer.XlatTable =
  73. (void **) I_RpcAllocate( RefIdToPointerEntries * sizeof(void *) );
  74. if ( ! pXlatTables->RefIdToPointer.XlatTable )
  75. fOutOfMemory = TRUE;
  76. else
  77. {
  78. MIDL_memset( pXlatTables->RefIdToPointer.XlatTable,
  79. 0,
  80. RefIdToPointerEntries * sizeof(void *) );
  81. pXlatTables->RefIdToPointer.StateTable =
  82. (uchar *) I_RpcAllocate( RefIdToPointerEntries * sizeof(uchar) );
  83. if ( ! pXlatTables->RefIdToPointer.StateTable )
  84. fOutOfMemory = TRUE;
  85. else
  86. {
  87. MIDL_memset( pXlatTables->RefIdToPointer.StateTable,
  88. 0,
  89. RefIdToPointerEntries * sizeof(uchar) );
  90. pXlatTables->RefIdToPointer.NumberOfEntries = RefIdToPointerEntries;
  91. //
  92. // Intialize the pointer to ref id tables.
  93. //
  94. pXlatTables->PointerToRefId.XlatTable =
  95. (PFULL_PTR_TO_REFID_ELEMENT *)
  96. I_RpcAllocate( PointerToRefIdBuckets *
  97. sizeof(PFULL_PTR_TO_REFID_ELEMENT) );
  98. if ( ! pXlatTables->PointerToRefId.XlatTable )
  99. fOutOfMemory = TRUE;
  100. else
  101. {
  102. MIDL_memset( pXlatTables->PointerToRefId.XlatTable,
  103. 0,
  104. PointerToRefIdBuckets * sizeof(PFULL_PTR_TO_REFID_ELEMENT) );
  105. }
  106. }
  107. }
  108. }
  109. if ( fOutOfMemory )
  110. {
  111. NdrFullPointerXlatFree( pXlatTables );
  112. if ( XlatSide == XLAT_SERVER )
  113. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  114. else
  115. {
  116. // The old compilers generate a code for the client side that
  117. // doesn't initialize the table pointer and the stub msg
  118. // initialization is after call to xlat initialize.
  119. // So, we are down to checking the pointer when used.
  120. return( 0 );
  121. }
  122. }
  123. pXlatTables->PointerToRefId.NumberOfBuckets = PointerToRefIdBuckets;
  124. pXlatTables->PointerToRefId.HashMask = PointerToRefIdBuckets - 1;
  125. pXlatTables->NextRefId = 1;
  126. pXlatTables->XlatSide = XlatSide;
  127. return pXlatTables;
  128. }
  129. void RPC_ENTRY
  130. NdrFullPointerXlatFree(
  131. PFULL_PTR_XLAT_TABLES pXlatTables )
  132. /***
  133. Routine description :
  134. Free the full pointer support data structures for an rpc call.
  135. Arguments :
  136. pXlatTables - Full pointer translation tables data structure to free.
  137. ***/
  138. {
  139. PFULL_PTR_TO_REFID_ELEMENT * HashTable;
  140. PFULL_PTR_TO_REFID_ELEMENT pElement, pTemp;
  141. ulong Buckets;
  142. ulong i;
  143. if ( ! pXlatTables )
  144. return;
  145. //
  146. // Free the ref id to pointer tables.
  147. //
  148. if ( pXlatTables->RefIdToPointer.XlatTable )
  149. I_RpcFree( pXlatTables->RefIdToPointer.XlatTable );
  150. if ( pXlatTables->RefIdToPointer.StateTable )
  151. I_RpcFree( pXlatTables->RefIdToPointer.StateTable );
  152. //
  153. // Free the pointer to ref id table.
  154. //
  155. HashTable = pXlatTables->PointerToRefId.XlatTable;
  156. if ( HashTable )
  157. {
  158. Buckets = pXlatTables->PointerToRefId.NumberOfBuckets;
  159. for ( i = 0; i < Buckets; i++ )
  160. if ( HashTable[i] )
  161. for ( pElement = HashTable[i]; pElement; pElement = pTemp )
  162. {
  163. pTemp = pElement->Next;
  164. I_RpcFree(pElement);
  165. }
  166. I_RpcFree( HashTable );
  167. }
  168. //
  169. // Free the translation table structure.
  170. //
  171. I_RpcFree( pXlatTables );
  172. }
  173. int RPC_ENTRY
  174. NdrFullPointerQueryPointer(
  175. PFULL_PTR_XLAT_TABLES pXlatTables,
  176. void * pPointer,
  177. uchar QueryType,
  178. ulong * pRefId )
  179. /***
  180. Routine description :
  181. This routine checks if a full pointer is in the full pointer translation
  182. table and is marked with the given state.
  183. If there is no current translation for this pointer then a translation is
  184. inserted in the given translation table and a ref id is assigned if pRefId
  185. is non-null.
  186. Arguments :
  187. pXlatTable - The full pointer translation tables.
  188. pPointer - The pointer to check.
  189. QueryType - The type of query, either FULL_POINTER_MARSHALLED or
  190. FULL_POINTER_BUF_SIZED.
  191. pRefId - The ref id for the pointer is returned if this parameter
  192. is non-null.
  193. Return Value :
  194. TRUE if the given pointer was null or a translation for the full pointer
  195. was found and had the QueryType set, FALSE otherwise.
  196. A return value of FALSE indicates that the pointee should be sized or
  197. marshalled.
  198. ***/
  199. {
  200. PFULL_PTR_TO_REFID_ELEMENT * HashTable;
  201. PFULL_PTR_TO_REFID_ELEMENT pElement;
  202. ulong HashTableIndex;
  203. if ( ! pPointer )
  204. {
  205. if ( pRefId )
  206. *pRefId = 0;
  207. return TRUE;
  208. }
  209. if ( ! pXlatTables )
  210. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  211. HashTable = pXlatTables->PointerToRefId.XlatTable;
  212. //
  213. // Lookup pPointer in PointerToRefId table.
  214. //
  215. HashTableIndex = PTR_HASH( pPointer, pXlatTables->PointerToRefId.HashMask );
  216. for ( pElement = HashTable[HashTableIndex];
  217. pElement;
  218. pElement = pElement->Next )
  219. {
  220. if ( pElement->Pointer == pPointer )
  221. {
  222. if ( CHECK_FULL_POINTER_STATE( pElement->State, QueryType ) )
  223. {
  224. if ( pRefId )
  225. *pRefId = pElement->RefId;
  226. return TRUE;
  227. }
  228. else
  229. {
  230. //
  231. // Assign a ref id now if it doesn't have one and pRefId is
  232. // non null.
  233. //
  234. if ( pRefId && ! pElement->RefId )
  235. pElement->RefId = pXlatTables->NextRefId++;
  236. SET_FULL_POINTER_STATE( pElement->State, QueryType );
  237. }
  238. break;
  239. }
  240. }
  241. //
  242. // If there is no translation for the pointer then insert a new one.
  243. //
  244. if ( ! pElement )
  245. {
  246. pElement = (PFULL_PTR_TO_REFID_ELEMENT)
  247. I_RpcAllocate( sizeof(FULL_PTR_TO_REFID_ELEMENT) );
  248. if ( ! pElement )
  249. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  250. pElement->State = 0;
  251. SET_FULL_POINTER_STATE( pElement->State, QueryType );
  252. pElement->Pointer = pPointer;
  253. if ( pRefId )
  254. pElement->RefId = pXlatTables->NextRefId++;
  255. else
  256. pElement->RefId = 0;
  257. pElement->Next = HashTable[HashTableIndex];
  258. HashTable[HashTableIndex] = pElement;
  259. }
  260. //
  261. // Set the ref id return value.
  262. //
  263. if ( pRefId )
  264. {
  265. //
  266. // We get here the first time we marshall a new full pointer.
  267. //
  268. *pRefId = pElement->RefId;
  269. //
  270. // We insert the reverse translation if we're on the client side.
  271. //
  272. if ( pXlatTables->XlatSide == XLAT_CLIENT )
  273. {
  274. if ( *pRefId >= pXlatTables->RefIdToPointer.NumberOfEntries )
  275. NdrFullPointerXlatRealloc( pXlatTables, *pRefId );
  276. pXlatTables->RefIdToPointer.XlatTable[*pRefId] = pPointer;
  277. }
  278. }
  279. return FALSE;
  280. }
  281. int RPC_ENTRY
  282. NdrFullPointerQueryRefId(
  283. PFULL_PTR_XLAT_TABLES pXlatTables,
  284. ulong RefId,
  285. uchar QueryType,
  286. void ** ppPointer )
  287. /***
  288. Routine description :
  289. This routine checks if a ref id is in the full pointer translation table
  290. and is marked with the given state.
  291. If a translation is found and ppPointer is non-null then *ppPointer is set
  292. to the value of the ref id's pointer value.
  293. If this routine returns FALSE for a FULL_POINTER_UNMARSHALLED query then
  294. the full pointer should be allocated and a call to
  295. NdrFullPointerInsertRefId must be made.
  296. If this routine returns FALSE for a FULL_POINTER_MEM_SIZED query then
  297. the size of the full pointer's pointee should be added to the current
  298. memory sizing calculation.
  299. Arguments :
  300. pXlatTable - The full pointer translation tables.
  301. pRefId - The ref id to search for.
  302. QueryType - The type of query, either FULL_POINTER_UNMARSHALLED or
  303. FULL_POINTER_MEM_SIZED.
  304. ppPointer - Holds the returned pointer value for the ref id if it is
  305. found.
  306. Return Value :
  307. TRUE if the ref id is 0 or a translation for the ref id is found and had
  308. the QueryType set, FALSE otherwise.
  309. A return value of FALSE indicates that the pointee should be sized or
  310. unmarshalled.
  311. ***/
  312. {
  313. uchar * StateTable;
  314. void * Pointer;
  315. if ( ! RefId )
  316. {
  317. return TRUE;
  318. }
  319. if ( ! pXlatTables )
  320. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  321. if ( RefId >= pXlatTables->NextRefId )
  322. pXlatTables->NextRefId = RefId + 1;
  323. if ( RefId >= pXlatTables->RefIdToPointer.NumberOfEntries )
  324. NdrFullPointerXlatRealloc( pXlatTables, RefId );
  325. StateTable = pXlatTables->RefIdToPointer.StateTable;
  326. Pointer = pXlatTables->RefIdToPointer.XlatTable[RefId];
  327. //
  328. // We make this check first. It's possible that we will already have
  329. // a translation for the ref id, but it simply won't be marked yet with
  330. // the proper state. In this case we still want to return the correct
  331. // pointer value from the translation tables, but we'll still end up
  332. // returning false when we make the state check.
  333. //
  334. if ( ppPointer )
  335. {
  336. //
  337. // We have to make sure and always copy the pointer's value from
  338. // the table. This way we handle the case when a pointer's VALUE
  339. // changes to a pointer which has a currently valid RefId (an
  340. // example of this could happen when a server swaps the values of
  341. // two [in,out] double pointers).
  342. //
  343. // Pointer will be null if this is the first time we've seen or used
  344. // this ref id.
  345. //
  346. *ppPointer = Pointer;
  347. }
  348. if ( CHECK_FULL_POINTER_STATE( StateTable[RefId], QueryType ) )
  349. {
  350. return TRUE;
  351. }
  352. else
  353. {
  354. SET_FULL_POINTER_STATE( StateTable[RefId], QueryType );
  355. return FALSE;
  356. }
  357. }
  358. void RPC_ENTRY
  359. NdrFullPointerInsertRefId(
  360. PFULL_PTR_XLAT_TABLES pXlatTables,
  361. ulong RefId,
  362. void * pPointer )
  363. /***
  364. Routine description :
  365. This routine inserts a ref id to pointer translation in the full pointer
  366. translation table.
  367. Arguments :
  368. pXlatTable - The full pointer translation tables.
  369. pRefId - The ref id.
  370. pPointer - The pointer.
  371. Return Value :
  372. None.
  373. ***/
  374. {
  375. // unused: uchar * StateTable;
  376. if ( ! pXlatTables )
  377. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  378. //
  379. // Ref id should be non-zero.
  380. //
  381. NDR_ASSERT( RefId, "NdrFullPointerInsertRefId : Ref id is zero" );
  382. //
  383. // Ref id should fit in the current table.
  384. //
  385. NDR_ASSERT( RefId < pXlatTables->RefIdToPointer.NumberOfEntries,
  386. "NdrFullPointerInsertRefId : Ref Id too large" );
  387. //
  388. // There should currently be no pointer translation for this ref id.
  389. //
  390. NDR_ASSERT( ! pXlatTables->RefIdToPointer.XlatTable[RefId],
  391. "NdrFullPointerInsertRefId : Translation already exists" );
  392. //
  393. // Insert the translation.
  394. //
  395. pXlatTables->RefIdToPointer.XlatTable[RefId] = pPointer;
  396. //
  397. // If we're on the server side then insert the inverse translation.
  398. //
  399. if ( pXlatTables->XlatSide == XLAT_SERVER )
  400. {
  401. PFULL_PTR_TO_REFID_ELEMENT pElement;
  402. long HashTableIndex;
  403. pElement = (PFULL_PTR_TO_REFID_ELEMENT)
  404. I_RpcAllocate( sizeof(FULL_PTR_TO_REFID_ELEMENT) );
  405. if ( ! pElement )
  406. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  407. pElement->State = 0;
  408. pElement->Pointer = pPointer;
  409. pElement->RefId = RefId;
  410. HashTableIndex = PTR_HASH( pPointer,
  411. pXlatTables->PointerToRefId.HashMask );
  412. pElement->Next = pXlatTables->PointerToRefId.XlatTable[HashTableIndex];
  413. pXlatTables->PointerToRefId.XlatTable[HashTableIndex] = pElement;
  414. }
  415. }
  416. int RPC_ENTRY
  417. NdrFullPointerFree(
  418. PFULL_PTR_XLAT_TABLES pXlatTables,
  419. void * pPointer )
  420. /***
  421. Routine description :
  422. Removes a full pointer from the translation tables, and frees it's
  423. associated translation data.
  424. Return value :
  425. TRUE if the pointer has not yet been freed or is null, FALSE otherwise.
  426. ***/
  427. {
  428. PFULL_PTR_TO_REFID_ELEMENT * HashTable;
  429. PFULL_PTR_TO_REFID_ELEMENT pElement;
  430. ulong HashTableIndex;
  431. if ( ! pPointer )
  432. return FALSE;
  433. if ( ! pXlatTables )
  434. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  435. HashTable = pXlatTables->PointerToRefId.XlatTable;
  436. //
  437. // Lookup pPointer in PointerToRefId table.
  438. //
  439. HashTableIndex = PTR_HASH( pPointer, pXlatTables->PointerToRefId.HashMask );
  440. for ( pElement = HashTable[HashTableIndex];
  441. pElement;
  442. pElement = pElement->Next )
  443. {
  444. if ( pElement->Pointer == pPointer )
  445. {
  446. if ( CHECK_FULL_POINTER_STATE(pElement->State,FULL_POINTER_FREED) )
  447. {
  448. return FALSE;
  449. }
  450. else
  451. {
  452. SET_FULL_POINTER_STATE(pElement->State,FULL_POINTER_FREED);
  453. return TRUE;
  454. }
  455. }
  456. }
  457. //
  458. // There is an instance when a full pointer is encountered for the first
  459. // time during freeing. This occurs if an [in] full pointer is changed
  460. // by the server manager routine. If this occurs we must insert the new
  461. // full pointer so we can keep track of it so that we don't free it more
  462. // than once.
  463. //
  464. pElement = (PFULL_PTR_TO_REFID_ELEMENT)
  465. I_RpcAllocate( sizeof(FULL_PTR_TO_REFID_ELEMENT) );
  466. if ( ! pElement )
  467. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  468. pElement->State = 0;
  469. pElement->Pointer = pPointer;
  470. HashTableIndex = PTR_HASH( pPointer,
  471. pXlatTables->PointerToRefId.HashMask );
  472. pElement->Next = pXlatTables->PointerToRefId.XlatTable[HashTableIndex];
  473. pXlatTables->PointerToRefId.XlatTable[HashTableIndex] = pElement;
  474. SET_FULL_POINTER_STATE( pElement->State, FULL_POINTER_FREED );
  475. return TRUE;
  476. }
  477. static void
  478. NdrFullPointerXlatRealloc(
  479. PFULL_PTR_XLAT_TABLES pXlatTables,
  480. ulong RefId)
  481. {
  482. void * pMemory;
  483. uint Entries;
  484. if ( ! pXlatTables )
  485. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  486. Entries = (uint) pXlatTables->RefIdToPointer.NumberOfEntries;
  487. // If the number is much larger than the previous one, most likely the
  488. // number is invalid. Before we have a concrete solution to replace the
  489. // current fixed array of RefIdToPointer lookup, this can catch most
  490. // of the failures.
  491. if ( RefId >= 2 * Entries )
  492. RpcRaiseException( RPC_X_BAD_STUB_DATA );
  493. //
  494. // Realloc RefIdToPointerTable. Allocate twice as many entries.
  495. //
  496. pMemory = I_RpcAllocate( Entries * sizeof(void *) * 2 );
  497. if ( ! pMemory )
  498. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  499. //
  500. // Now copy the current entries into the new memory.
  501. //
  502. RpcpMemoryCopy( pMemory,
  503. pXlatTables->RefIdToPointer.XlatTable,
  504. Entries * sizeof( void * ) );
  505. //
  506. // Set the new entries to 0.
  507. //
  508. MIDL_memset( (char *) pMemory + Entries * sizeof( void *),
  509. 0,
  510. Entries * sizeof( void *) );
  511. //
  512. // Free the old table.
  513. //
  514. I_RpcFree( pXlatTables->RefIdToPointer.XlatTable );
  515. //
  516. // Get the new table.
  517. //
  518. pXlatTables->RefIdToPointer.XlatTable = (void**)pMemory;
  519. //
  520. // Realloc RefIdToPointerState
  521. //
  522. pMemory = I_RpcAllocate( Entries * sizeof(uchar) * 2 );
  523. if ( ! pMemory )
  524. RpcRaiseException( RPC_S_OUT_OF_MEMORY );
  525. //
  526. // Now copy the current entries into the new memory.
  527. //
  528. RpcpMemoryCopy( pMemory,
  529. pXlatTables->RefIdToPointer.StateTable,
  530. Entries * sizeof(uchar) );
  531. //
  532. // Set the new entries to 0.
  533. //
  534. MIDL_memset( (char *) pMemory + Entries * sizeof(uchar),
  535. 0,
  536. Entries * sizeof(uchar) );
  537. //
  538. // Free the old table.
  539. //
  540. I_RpcFree( pXlatTables->RefIdToPointer.StateTable );
  541. //
  542. // Get the new table.
  543. //
  544. pXlatTables->RefIdToPointer.StateTable = (uchar*)pMemory;
  545. //
  546. // Update number of entries.
  547. //
  548. pXlatTables->RefIdToPointer.NumberOfEntries *= 2;
  549. }