Leaked source code of windows server 2003
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.

646 lines
20 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation
  3. Module Name:
  4. sxsactctx.c
  5. Abstract:
  6. Side-by-side activation support for Windows/NT
  7. Implementation of the application context object.
  8. Author:
  9. Michael Grier (MGrier) 2/1/2000
  10. Revision History:
  11. --*/
  12. #if defined(__cplusplus)
  13. extern "C" {
  14. #endif
  15. #pragma warning(disable:4214) // bit field types other than int
  16. #pragma warning(disable:4201) // nameless struct/union
  17. #pragma warning(disable:4115) // named type definition in parentheses
  18. #pragma warning(disable:4127) // condition expression is constant
  19. #include <ntos.h>
  20. #include <ntrtl.h>
  21. #include <nturtl.h>
  22. #include <sxstypes.h>
  23. #include "sxsp.h"
  24. #include "limits.h"
  25. #define IS_ALIGNED(_p, _n) ((((ULONG_PTR) (_p)) & ((_n) - 1)) == 0)
  26. #define IS_WORD_ALIGNED(_p) IS_ALIGNED((_p), 2)
  27. #define IS_DWORD_ALIGNED(_p) IS_ALIGNED((_p), 4)
  28. BOOLEAN g_SxsKeepActivationContextsAlive;
  29. BOOLEAN g_SxsTrackReleaseStacks;
  30. // These must be accessed -only- with the peb lock held
  31. LIST_ENTRY g_SxsLiveActivationContexts;
  32. LIST_ENTRY g_SxsFreeActivationContexts;
  33. ULONG g_SxsMaxDeadActivationContexts = ULONG_MAX;
  34. ULONG g_SxsCurrentDeadActivationContexts;
  35. #if DBG
  36. VOID RtlpSxsBreakOnInvalidMarker(PCACTIVATION_CONTEXT ActivationContext, ULONG FailureCode);
  37. static CHAR *SxsSteppedOnMarkerText =
  38. "%s : Invalid activation context marker %p found in activation context %p\n"
  39. " This means someone stepped on the allocation, or someone is using a\n"
  40. " deallocated activation context\n";
  41. #define VALIDATE_ACTCTX(pA) do { \
  42. const PACTIVATION_CONTEXT_WRAPPED pActual = CONTAINING_RECORD(pA, ACTIVATION_CONTEXT_WRAPPED, ActivationContext); \
  43. if (pActual->MagicMarker != ACTCTX_MAGIC_MARKER) { \
  44. DbgPrint(SxsSteppedOnMarkerText, __FUNCTION__, pActual->MagicMarker, pA); \
  45. ASSERT(pActual->MagicMarker == ACTCTX_MAGIC_MARKER); \
  46. RtlpSxsBreakOnInvalidMarker((pA), SXS_CORRUPTION_ACTCTX_MAGIC_NOT_MATCHED); \
  47. } \
  48. } while (0)
  49. #else
  50. #define VALIDATE_ACTCTX(pA)
  51. #endif
  52. VOID
  53. FASTCALL
  54. RtlpMoveActCtxToFreeList(
  55. PACTIVATION_CONTEXT ActCtx
  56. );
  57. VOID
  58. FASTCALL
  59. RtlpPlaceActivationContextOnLiveList(
  60. PACTIVATION_CONTEXT ActCtx
  61. );
  62. NTSTATUS
  63. RtlpValidateActivationContextData(
  64. IN ULONG Flags,
  65. IN PCACTIVATION_CONTEXT_DATA Data,
  66. IN SIZE_T BufferSize OPTIONAL
  67. )
  68. {
  69. NTSTATUS Status = STATUS_SUCCESS;
  70. PCACTIVATION_CONTEXT_DATA_TOC_HEADER TocHeader;
  71. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
  72. if (Flags != 0) {
  73. Status = STATUS_INVALID_PARAMETER;
  74. goto Exit;
  75. }
  76. if ((Data->Magic != ACTIVATION_CONTEXT_DATA_MAGIC) ||
  77. (Data->FormatVersion != ACTIVATION_CONTEXT_DATA_FORMAT_WHISTLER) ||
  78. ((BufferSize != 0) &&
  79. (BufferSize < Data->TotalSize))) {
  80. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  81. goto Exit;
  82. }
  83. // Check required elements...
  84. if ((Data->DefaultTocOffset == 0) ||
  85. !IS_DWORD_ALIGNED(Data->DefaultTocOffset)) {
  86. DbgPrintEx(
  87. DPFLTR_SXS_ID,
  88. DPFLTR_ERROR_LEVEL,
  89. "SXS: Warning: Activation context data at %p missing default TOC\n", Data);
  90. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  91. goto Exit;
  92. }
  93. // How can we not have an assembly roster?
  94. if ((Data->AssemblyRosterOffset == 0) ||
  95. !IS_DWORD_ALIGNED(Data->AssemblyRosterOffset)) {
  96. DbgPrintEx(
  97. DPFLTR_SXS_ID,
  98. DPFLTR_ERROR_LEVEL,
  99. "SXS: Warning: Activation context data at %p lacks assembly roster\n", Data);
  100. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  101. goto Exit;
  102. }
  103. if (Data->DefaultTocOffset != 0) {
  104. if ((Data->DefaultTocOffset >= Data->TotalSize) ||
  105. ((Data->DefaultTocOffset + sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) > Data->TotalSize)) {
  106. DbgPrintEx(
  107. DPFLTR_SXS_ID,
  108. DPFLTR_ERROR_LEVEL,
  109. "SXS: Activation context data at %p has invalid TOC header offset\n", Data);
  110. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  111. goto Exit;
  112. }
  113. TocHeader = (PCACTIVATION_CONTEXT_DATA_TOC_HEADER) (((ULONG_PTR) Data) + Data->DefaultTocOffset);
  114. if (TocHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) {
  115. DbgPrintEx(
  116. DPFLTR_SXS_ID,
  117. DPFLTR_ERROR_LEVEL,
  118. "SXS: Activation context data at %p has TOC header too small (%lu)\n", Data, TocHeader->HeaderSize);
  119. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  120. goto Exit;
  121. }
  122. if ((TocHeader->FirstEntryOffset >= Data->TotalSize) ||
  123. (!IS_DWORD_ALIGNED(TocHeader->FirstEntryOffset)) ||
  124. ((TocHeader->FirstEntryOffset + (TocHeader->EntryCount * sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY))) > Data->TotalSize)) {
  125. DbgPrintEx(
  126. DPFLTR_SXS_ID,
  127. DPFLTR_ERROR_LEVEL,
  128. "SXS: Activation context data at %p has invalid TOC entry array offset\n", Data);
  129. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  130. goto Exit;
  131. }
  132. }
  133. // we should finish validating the rest of the structure...
  134. if ((Data->AssemblyRosterOffset >= Data->TotalSize) ||
  135. ((Data->AssemblyRosterOffset + sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) > Data->TotalSize)) {
  136. DbgPrintEx(
  137. DPFLTR_SXS_ID,
  138. DPFLTR_ERROR_LEVEL,
  139. "SXS: Activation context data at %p has invalid assembly roster offset\n", Data);
  140. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  141. goto Exit;
  142. }
  143. AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) Data) + Data->AssemblyRosterOffset);
  144. if (Data->AssemblyRosterOffset != 0) {
  145. if (AssemblyRosterHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) {
  146. DbgPrintEx(
  147. DPFLTR_SXS_ID,
  148. DPFLTR_ERROR_LEVEL,
  149. "SXS: Activation context data at %p has assembly roster header too small (%lu)\n", Data, AssemblyRosterHeader->HeaderSize);
  150. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  151. goto Exit;
  152. }
  153. }
  154. Status = STATUS_SUCCESS;
  155. Exit:
  156. return Status;
  157. }
  158. NTSTATUS
  159. NTAPI
  160. RtlCreateActivationContext(
  161. IN ULONG Flags,
  162. IN PCACTIVATION_CONTEXT_DATA ActivationContextData,
  163. IN ULONG ExtraBytes,
  164. IN PACTIVATION_CONTEXT_NOTIFY_ROUTINE NotificationRoutine,
  165. IN PVOID NotificationContext,
  166. OUT PACTIVATION_CONTEXT *ActCtx
  167. )
  168. {
  169. PACTIVATION_CONTEXT NewActCtx = NULL;
  170. PACTIVATION_CONTEXT_WRAPPED AllocatedActCtx = NULL;
  171. NTSTATUS Status = STATUS_SUCCESS;
  172. ULONG i, j;
  173. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
  174. BOOLEAN UninitializeStorageMapOnExit = FALSE;
  175. DbgPrintEx(
  176. DPFLTR_SXS_ID,
  177. DPFLTR_TRACE_LEVEL,
  178. "SXS: RtlCreateActivationContext() called with parameters:\n"
  179. " Flags = 0x%08lx\n"
  180. " ActivationContextData = %p\n"
  181. " ExtraBytes = %lu\n"
  182. " NotificationRoutine = %p\n"
  183. " NotificationContext = %p\n"
  184. " ActCtx = %p\n",
  185. Flags,
  186. ActivationContextData,
  187. ExtraBytes,
  188. NotificationRoutine,
  189. NotificationContext,
  190. ActCtx);
  191. RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT_DATA(ActivationContextData);
  192. if (ActCtx != NULL)
  193. *ActCtx = NULL;
  194. if ((Flags != 0) ||
  195. (ActivationContextData == NULL) ||
  196. (ExtraBytes > 65536) ||
  197. (ActCtx == NULL))
  198. {
  199. Status = STATUS_INVALID_PARAMETER;
  200. goto Exit;
  201. }
  202. // Make sure that the activation context data passes muster
  203. Status = RtlpValidateActivationContextData(0, ActivationContextData, 0);
  204. if (!NT_SUCCESS(Status))
  205. goto Exit;
  206. // Allocate enough space to hold the new activation context, plus space for the 'magic'
  207. // marker
  208. AllocatedActCtx = (PACTIVATION_CONTEXT_WRAPPED)RtlAllocateHeap(
  209. RtlProcessHeap(),
  210. 0,
  211. sizeof(ACTIVATION_CONTEXT_WRAPPED) + ExtraBytes);
  212. if (AllocatedActCtx == NULL)
  213. {
  214. Status = STATUS_NO_MEMORY;
  215. goto Exit;
  216. }
  217. // Get the new activation context object, then stamp in the magic signature
  218. NewActCtx = &AllocatedActCtx->ActivationContext;
  219. AllocatedActCtx->MagicMarker = ACTCTX_MAGIC_MARKER;
  220. AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) ActivationContextData) + ActivationContextData->AssemblyRosterOffset);
  221. Status = RtlpInitializeAssemblyStorageMap(
  222. &NewActCtx->StorageMap,
  223. AssemblyRosterHeader->EntryCount,
  224. (AssemblyRosterHeader->EntryCount > NUMBER_OF(NewActCtx->InlineStorageMapEntries)) ? NULL : NewActCtx->InlineStorageMapEntries);
  225. if (!NT_SUCCESS(Status))
  226. goto Exit;
  227. UninitializeStorageMapOnExit = TRUE;
  228. NewActCtx->RefCount = 1;
  229. NewActCtx->Flags = 0;
  230. NewActCtx->ActivationContextData = (PCACTIVATION_CONTEXT_DATA) ActivationContextData;
  231. NewActCtx->NotificationRoutine = NotificationRoutine;
  232. NewActCtx->NotificationContext = NotificationContext;
  233. for (i=0; i<NUMBER_OF(NewActCtx->SentNotifications); i++)
  234. NewActCtx->SentNotifications[i] = 0;
  235. for (i=0; i<NUMBER_OF(NewActCtx->DisabledNotifications); i++)
  236. NewActCtx->DisabledNotifications[i] = 0;
  237. for (i=0; i<ACTCTX_RELEASE_STACK_SLOTS; i++)
  238. for (j=0; j<ACTCTX_RELEASE_STACK_DEPTH; j++)
  239. NewActCtx->StackTraces[i][j] = NULL;
  240. NewActCtx->StackTraceIndex = 0;
  241. if (g_SxsKeepActivationContextsAlive) {
  242. RtlpPlaceActivationContextOnLiveList(NewActCtx);
  243. }
  244. *ActCtx = &AllocatedActCtx->ActivationContext;
  245. AllocatedActCtx = NULL;
  246. UninitializeStorageMapOnExit = FALSE;
  247. Status = STATUS_SUCCESS;
  248. Exit:
  249. if (AllocatedActCtx != NULL) {
  250. if (UninitializeStorageMapOnExit) {
  251. RtlpUninitializeAssemblyStorageMap(&AllocatedActCtx->ActivationContext.StorageMap);
  252. }
  253. RtlFreeHeap(RtlProcessHeap(), 0, AllocatedActCtx);
  254. }
  255. return Status;
  256. }
  257. VOID
  258. NTAPI
  259. RtlAddRefActivationContext(
  260. PACTIVATION_CONTEXT ActCtx
  261. )
  262. {
  263. if ((ActCtx != NULL) &&
  264. (!IS_SPECIAL_ACTCTX(ActCtx)) &&
  265. (ActCtx->RefCount != LONG_MAX))
  266. {
  267. LONG NewRefCount = LONG_MAX;
  268. VALIDATE_ACTCTX(ActCtx);
  269. for (;;)
  270. {
  271. LONG OldRefCount = ActCtx->RefCount;
  272. ASSERT(OldRefCount > 0);
  273. if (OldRefCount == LONG_MAX)
  274. {
  275. NewRefCount = LONG_MAX;
  276. break;
  277. }
  278. NewRefCount = OldRefCount + 1;
  279. if (InterlockedCompareExchange(&ActCtx->RefCount, NewRefCount, OldRefCount) == OldRefCount)
  280. break;
  281. }
  282. ASSERT(NewRefCount > 0);
  283. }
  284. }
  285. VOID
  286. NTAPI
  287. RtlpFreeActivationContext(
  288. PACTIVATION_CONTEXT ActCtx
  289. )
  290. {
  291. VALIDATE_ACTCTX(ActCtx);
  292. ASSERT(ActCtx->RefCount == 0);
  293. BOOLEAN DisableNotification = FALSE;
  294. if (ActCtx->NotificationRoutine != NULL) {
  295. // There's no need to check for the notification being disabled; destroy
  296. // notifications are sent only once, so if the notification routine is not
  297. // null, we can just call it.
  298. (*(ActCtx->NotificationRoutine))(
  299. ACTIVATION_CONTEXT_NOTIFICATION_DESTROY,
  300. ActCtx,
  301. ActCtx->ActivationContextData,
  302. ActCtx->NotificationContext,
  303. NULL,
  304. &DisableNotification);
  305. }
  306. RtlpUninitializeAssemblyStorageMap(&ActCtx->StorageMap);
  307. //
  308. // This predates the MAXULONG refcount, maybe we can get rid of the the flag now?
  309. //
  310. if ((ActCtx->Flags & ACTIVATION_CONTEXT_NOT_HEAP_ALLOCATED) == 0) {
  311. RtlFreeHeap(RtlProcessHeap(), 0, CONTAINING_RECORD(ActCtx, ACTIVATION_CONTEXT_WRAPPED, ActivationContext));
  312. }
  313. }
  314. VOID
  315. NTAPI
  316. RtlReleaseActivationContext(
  317. PACTIVATION_CONTEXT ActCtx
  318. )
  319. {
  320. if ((ActCtx != NULL) &&
  321. (!IS_SPECIAL_ACTCTX(ActCtx)) &&
  322. (ActCtx->RefCount > 0) &&
  323. (ActCtx->RefCount != LONG_MAX))
  324. {
  325. LONG NewRefCount = LONG_MAX;
  326. ULONG StackTraceSlot = 0;
  327. VALIDATE_ACTCTX(ActCtx);
  328. // Complicated version of InterlockedDecrement that won't decrement LONG_MAX
  329. for (;;)
  330. {
  331. LONG OldRefCount = ActCtx->RefCount;
  332. ASSERT(OldRefCount != 0);
  333. if (OldRefCount == LONG_MAX)
  334. {
  335. NewRefCount = OldRefCount;
  336. break;
  337. }
  338. NewRefCount = OldRefCount - 1;
  339. if (InterlockedCompareExchange(&ActCtx->RefCount, NewRefCount, OldRefCount) == OldRefCount)
  340. break;
  341. }
  342. // This spiffiness will capture the last N releases of this activation context, in
  343. // a circular list fashion. Just look at ((ActCtx->StackTraceIndex - 1) % ACTCTX_RELEASE_STACK_SLOTS)
  344. // to find the most recent release call. This is especially handy for people who over-release.
  345. if (g_SxsTrackReleaseStacks)
  346. {
  347. StackTraceSlot = ((ULONG)InterlockedIncrement((LONG*)&ActCtx->StackTraceIndex)) % ACTCTX_RELEASE_STACK_SLOTS;
  348. RtlCaptureStackBackTrace(1, ACTCTX_RELEASE_STACK_DEPTH, ActCtx->StackTraces[StackTraceSlot], NULL);
  349. }
  350. if (NewRefCount == 0)
  351. {
  352. // If this flag is set, then we need to put "dead" activation
  353. // contexts into this special list. This should help us diagnose
  354. // actctx over-releasing better. Don't do this if we haven't
  355. // initialized the list head yet.
  356. if (g_SxsKeepActivationContextsAlive) {
  357. RtlpMoveActCtxToFreeList(ActCtx);
  358. }
  359. // Otherwise, just free it.
  360. else {
  361. RtlpFreeActivationContext(ActCtx);
  362. }
  363. }
  364. }
  365. }
  366. NTSTATUS
  367. NTAPI
  368. RtlZombifyActivationContext(
  369. PACTIVATION_CONTEXT ActCtx
  370. )
  371. {
  372. NTSTATUS Status = STATUS_SUCCESS;
  373. if ((ActCtx == NULL) || IS_SPECIAL_ACTCTX(ActCtx))
  374. {
  375. Status = STATUS_INVALID_PARAMETER;
  376. goto Exit;
  377. }
  378. VALIDATE_ACTCTX(ActCtx);
  379. if ((ActCtx->Flags & ACTIVATION_CONTEXT_ZOMBIFIED) == 0)
  380. {
  381. if (ActCtx->NotificationRoutine != NULL)
  382. {
  383. // Since disable is sent only once, there's no need to check for
  384. // disabled notifications.
  385. BOOLEAN DisableNotification = FALSE;
  386. (*(ActCtx->NotificationRoutine))(
  387. ACTIVATION_CONTEXT_NOTIFICATION_ZOMBIFY,
  388. ActCtx,
  389. ActCtx->ActivationContextData,
  390. ActCtx->NotificationContext,
  391. NULL,
  392. &DisableNotification);
  393. }
  394. ActCtx->Flags |= ACTIVATION_CONTEXT_ZOMBIFIED;
  395. }
  396. Status = STATUS_SUCCESS;
  397. Exit:
  398. return Status;
  399. }
  400. VOID
  401. FASTCALL
  402. RtlpEnsureLiveDeadListsInitialized(
  403. VOID
  404. )
  405. {
  406. if (g_SxsLiveActivationContexts.Flink == NULL) {
  407. RtlAcquirePebLock();
  408. __try {
  409. if (g_SxsLiveActivationContexts.Flink != NULL)
  410. __leave;
  411. InitializeListHead(&g_SxsLiveActivationContexts);
  412. InitializeListHead(&g_SxsFreeActivationContexts);
  413. }
  414. __finally {
  415. RtlReleasePebLock();
  416. }
  417. }
  418. }
  419. // PRECONDITION: Called only when g_SxsKeepActivationContextsAlive is set, but not dangerous
  420. // to call at other times, just nonperformant
  421. VOID
  422. FASTCALL
  423. RtlpMoveActCtxToFreeList(
  424. PACTIVATION_CONTEXT ActCtx
  425. )
  426. {
  427. RtlpEnsureLiveDeadListsInitialized();
  428. RtlAcquirePebLock();
  429. __try {
  430. // Remove this entry from whatever list it's on. This works fine for entries that were
  431. // never on any list as well.
  432. RemoveEntryList(&ActCtx->Links);
  433. // If we are about to overflow the "max dead count" and there's items on the
  434. // dead list to clear out, start clearing out entries until we're underwater
  435. // again.
  436. while ((g_SxsCurrentDeadActivationContexts != 0) &&
  437. (g_SxsCurrentDeadActivationContexts >= g_SxsMaxDeadActivationContexts)) {
  438. LIST_ENTRY *ple2 = RemoveHeadList(&g_SxsFreeActivationContexts);
  439. PACTIVATION_CONTEXT ActToFree = CONTAINING_RECORD(ple2, ACTIVATION_CONTEXT, Links);
  440. // If this assert fires, then "something bad" happened while walking the list
  441. ASSERT(ple2 != &g_SxsFreeActivationContexts);
  442. RtlpFreeActivationContext(ActToFree);
  443. g_SxsCurrentDeadActivationContexts--;
  444. }
  445. // Now, if the max dead count is greater than zero, add this to the dead list
  446. if (g_SxsMaxDeadActivationContexts > 0) {
  447. InsertTailList(&g_SxsFreeActivationContexts, &ActCtx->Links);
  448. g_SxsCurrentDeadActivationContexts++;
  449. }
  450. // Otherwise, just free it
  451. else {
  452. RtlpFreeActivationContext(ActCtx);
  453. }
  454. }
  455. __finally {
  456. RtlReleasePebLock();
  457. }
  458. }
  459. // PRECONDITION: g_SxsKeepActivationContextsAlive set. Not dangerous to call when not set,
  460. // just underperformant.
  461. VOID
  462. FASTCALL
  463. RtlpPlaceActivationContextOnLiveList(
  464. PACTIVATION_CONTEXT ActCtx
  465. )
  466. {
  467. // Ensure these are initialized.
  468. RtlpEnsureLiveDeadListsInitialized();
  469. RtlAcquirePebLock();
  470. __try {
  471. InsertHeadList(&g_SxsLiveActivationContexts, &ActCtx->Links);
  472. }
  473. __finally {
  474. RtlReleasePebLock();
  475. }
  476. }
  477. VOID
  478. FASTCALL
  479. RtlpFreeCachedActivationContexts(
  480. VOID
  481. )
  482. {
  483. LIST_ENTRY *ple = NULL;
  484. // Don't bother if these were never initialized
  485. if ((g_SxsLiveActivationContexts.Flink == NULL) || (g_SxsFreeActivationContexts.Flink == NULL))
  486. return;
  487. RtlAcquirePebLock();
  488. __try {
  489. ple = g_SxsLiveActivationContexts.Flink;
  490. while (ple != &g_SxsLiveActivationContexts) {
  491. PACTIVATION_CONTEXT ActCtx = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT, Links);
  492. ple = ActCtx->Links.Flink;
  493. RemoveEntryList(&ActCtx->Links);
  494. RtlpFreeActivationContext(ActCtx);
  495. }
  496. ple = g_SxsFreeActivationContexts.Flink;
  497. while (ple != &g_SxsFreeActivationContexts) {
  498. PACTIVATION_CONTEXT ActCtx = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT, Links);
  499. ple = ActCtx->Links.Flink;
  500. RemoveEntryList(&ActCtx->Links);
  501. RtlpFreeActivationContext(ActCtx);
  502. }
  503. }
  504. __finally {
  505. RtlReleasePebLock();
  506. }
  507. }
  508. #if DBG
  509. VOID
  510. RtlpSxsBreakOnInvalidMarker(
  511. PCACTIVATION_CONTEXT ActivationContext,
  512. ULONG FailureCode
  513. )
  514. {
  515. EXCEPTION_RECORD Exr;
  516. Exr.ExceptionRecord = NULL;
  517. Exr.ExceptionCode = STATUS_SXS_CORRUPTION;
  518. Exr.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  519. Exr.NumberParameters = 3;
  520. Exr.ExceptionInformation[0] = SXS_CORRUPTION_ACTCTX_MAGIC;
  521. Exr.ExceptionInformation[1] = FailureCode;
  522. Exr.ExceptionInformation[2] = (ULONG_PTR)ActivationContext;
  523. RtlRaiseException(&Exr);
  524. }
  525. #endif
  526. #if defined(__cplusplus)
  527. } /* extern "C" */
  528. #endif