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.

697 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sxsctxact.c
  5. Abstract:
  6. Side-by-side activation support for Windows/NT
  7. Implementation of context activation/deactivation
  8. Author:
  9. Michael Grier (MGrier) 2/2/2000
  10. Revision History:
  11. --*/
  12. #include <ntos.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <sxstypes.h>
  16. #include "sxsp.h"
  17. #if NT_SXS_PERF_COUNTERS_ENABLED
  18. #if defined(_X86_)
  19. __inline
  20. ULONGLONG
  21. RtlpGetCycleCount(void)
  22. {
  23. __asm {
  24. RDTSC
  25. }
  26. }
  27. #else
  28. __inline
  29. ULONGLONG
  30. RtlpGetCycleCount(void)
  31. {
  32. return 0;
  33. }
  34. #endif // defined(_X86_)
  35. #endif // NT_SXS_PERF_COUNTERS_ENABLED
  36. // DWORD just so that in the debugger we don't have to guess the size...
  37. ULONG RtlpCaptureActivationContextActivationStacks =
  38. #if DBG
  39. TRUE
  40. #else
  41. FALSE
  42. #endif
  43. ;
  44. //
  45. // APPCOMPAT: Setting this flag to TRUE indicates that we no longer allow
  46. // skipping over "unactivated" (ie: multiple activation) context frames.
  47. // The default action should be FALSE, which will let mutliply-activated
  48. // contexts slide by.
  49. //
  50. // WARNING: This allows app authors to be a little sleazy about their activate
  51. // and deactivate pairs.
  52. //
  53. BOOLEAN RtlpNotAllowingMultipleActivation = FALSE;
  54. NTSTATUS
  55. RtlpAllocateActivationContextStackFrame(
  56. IN ULONG Flags,
  57. PTEB Teb,
  58. OUT PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME *FrameOut
  59. )
  60. {
  61. NTSTATUS Status = STATUS_INTERNAL_ERROR;
  62. LIST_ENTRY *ple;
  63. PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = NULL;
  64. ULONG i;
  65. if (FrameOut != NULL)
  66. *FrameOut = NULL;
  67. ASSERT((Flags == 0) && (FrameOut != NULL) && (Teb != NULL));
  68. if ((Flags != 0) || (FrameOut == NULL) || (Teb == NULL)) {
  69. Status = STATUS_INVALID_PARAMETER;
  70. goto Exit;
  71. }
  72. for (ple = Teb->ActivationContextStack.FrameListCache.Flink; ple != &Teb->ActivationContextStack.FrameListCache; ple = ple->Flink) {
  73. PACTIVATION_CONTEXT_STACK_FRAMELIST FrameList = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT_STACK_FRAMELIST, Links);
  74. for (i=0; i<RTL_NUMBER_OF(FrameList->Frames); i++) {
  75. if (FrameList->Frames[i].Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST) {
  76. ASSERT(FrameList->FramesInUse != NUMBER_OF(FrameList->Frames));
  77. FrameList->FramesInUse++;
  78. Frame = &FrameList->Frames[i];
  79. break;
  80. }
  81. }
  82. if (Frame != NULL)
  83. break;
  84. }
  85. if (Frame == NULL) {
  86. // No space left; allocate a new framelist...
  87. PACTIVATION_CONTEXT_STACK_FRAMELIST FrameList = RtlAllocateHeap(RtlProcessHeap(), 0, sizeof(ACTIVATION_CONTEXT_STACK_FRAMELIST));
  88. if (FrameList == NULL) {
  89. Status = STATUS_NO_MEMORY;
  90. goto Exit;
  91. }
  92. for (i=0; i<RTL_NUMBER_OF(FrameList->Frames); i++) {
  93. FrameList->Frames[i].Frame.Previous = NULL;
  94. FrameList->Frames[i].Frame.ActivationContext = NULL;
  95. FrameList->Frames[i].Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST | RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED;
  96. FrameList->Frames[i].Cookie = 0;
  97. }
  98. Frame = &FrameList->Frames[0];
  99. FrameList->FramesInUse = 1;
  100. InsertHeadList(&Teb->ActivationContextStack.FrameListCache, &FrameList->Links);
  101. }
  102. ASSERT((Frame != NULL) && (Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST));
  103. Frame->Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED;
  104. *FrameOut = Frame;
  105. Status = STATUS_SUCCESS;
  106. Exit:
  107. return Status;
  108. }
  109. VOID
  110. RtlpFreeActivationContextStackFrame(
  111. PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame
  112. )
  113. {
  114. LIST_ENTRY *ple = NULL;
  115. PTEB Teb = NtCurrentTeb();
  116. ASSERT(Frame != NULL);
  117. if (Frame != NULL) {
  118. // If this assert fires, someone's trying to free an already freed frame. Or someone's set the
  119. // "I'm on the free list" flag in the frame data.
  120. ASSERT(!(Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST));
  121. if (!(Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST)) {
  122. for (ple = Teb->ActivationContextStack.FrameListCache.Flink; ple != &Teb->ActivationContextStack.FrameListCache; ple = ple->Flink) {
  123. PACTIVATION_CONTEXT_STACK_FRAMELIST FrameList = CONTAINING_RECORD(ple, ACTIVATION_CONTEXT_STACK_FRAMELIST, Links);
  124. // A frame list with zero frames shouldn't be on the list!
  125. ASSERT(FrameList->FramesInUse > 0);
  126. if ((Frame >= &FrameList->Frames[0]) &&
  127. (Frame < &FrameList->Frames[RTL_NUMBER_OF(FrameList->Frames)])) {
  128. // It's in this frame list; look for it!
  129. ULONG i = (ULONG)(Frame - FrameList->Frames);
  130. // If this assert fires, it means that the frame pointer passed in should have been a frame
  131. // in this framelist, but it actually didn't point to any of the array entries exactly.
  132. // Probably someone munged the pointer.
  133. ASSERT(Frame == &FrameList->Frames[i]);
  134. if ((Frame == &FrameList->Frames[i]) && (FrameList->FramesInUse > 0)) {
  135. FrameList->FramesInUse--;
  136. Frame->Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_ON_FREE_LIST;
  137. if (FrameList->FramesInUse == 0) {
  138. RemoveEntryList(ple);
  139. RtlFreeHeap(RtlProcessHeap(), 0, FrameList);
  140. }
  141. }
  142. // No sense continuing the search on the list; we've found the one.
  143. break;
  144. }
  145. }
  146. // If we ran off the end of the list, it must have been a bogus frame pointer.
  147. ASSERT(ple != &Teb->ActivationContextStack.FrameListCache);
  148. }
  149. }
  150. }
  151. #if !defined(INVALID_HANDLE_VALUE)
  152. #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
  153. #endif // !defined(INVALID_HANDLE_VALUE)
  154. //
  155. // Define magic cookie values returned by RtlActivateActivationContext*() that
  156. // represent a failure to activate the requested context. The notable thing
  157. // is that on deactivation via the cookie, we need to know whether to leave
  158. // querying disabled or whether to enable it, thus the two magic values.
  159. //
  160. // The top nibble of the cookie denotes its type: normal, default-pushed or failed
  161. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_NORMAL (1)
  162. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_DUPLICATE_ACTIVATION (2)
  163. #define ULONG_PTR_IZE(_x) ((ULONG_PTR) (_x))
  164. #define ULONG_PTR_IZE_SHIFT_AND_MASK(_x, _shift, _mask) ((ULONG_PTR) ((ULONG_PTR_IZE((_x)) & (_mask)) << (_shift)))
  165. //
  166. // We only use the lower 12 bits of the thread id, but that should be unique enough;
  167. // this is really for debugging aids; if your tests pass such that you're
  168. // erroneously passing activation context cookies between threads that happen to
  169. // match up in their lower 12 bits of their thread id, you're pretty darned
  170. // lucky.
  171. //
  172. #define CHAR_BITS 8
  173. #define BIT_LENGTH(x) (sizeof(x) * CHAR_BITS)
  174. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_LENGTH (4)
  175. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_OFFSET (BIT_LENGTH(PVOID) - ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_LENGTH)
  176. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_MASK ((1 << ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_LENGTH) - 1)
  177. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_LENGTH ((BIT_LENGTH(PVOID) / 2) - ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_LENGTH)
  178. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_OFFSET (ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_OFFSET - ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_LENGTH)
  179. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_MASK ((1 << ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_LENGTH) - 1)
  180. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_LENGTH (BIT_LENGTH(PVOID) - (ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_LENGTH + ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_LENGTH))
  181. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_OFFSET (0)
  182. #define ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_MASK ((1 << ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_LENGTH) - 1)
  183. // Never try to use more than 32 bits for the TID field.
  184. C_ASSERT(ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_LENGTH <= BIT_LENGTH(ULONG));
  185. #define MAKE_ACTIVATION_CONTEXT_ACTIVATION_COOKIE(_type, _teb, _code) \
  186. ((ULONG_PTR) ( \
  187. ULONG_PTR_IZE_SHIFT_AND_MASK((_type), ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_OFFSET, ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_BIT_MASK) | \
  188. ULONG_PTR_IZE_SHIFT_AND_MASK((HandleToUlong((_teb)->ClientId.UniqueThread)), ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_OFFSET, ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_MASK) | \
  189. ULONG_PTR_IZE_SHIFT_AND_MASK((_code), ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_OFFSET, ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE_BIT_MASK)))
  190. #define EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_FIELD(_x, _fieldname) (ULONG_PTR_IZE((ULONG_PTR_IZE((_x)) >> ACTIVATION_CONTEXT_ACTIVATION_COOKIE_ ## _fieldname ## _BIT_OFFSET)) & ACTIVATION_CONTEXT_ACTIVATION_COOKIE_ ## _fieldname ## _BIT_MASK)
  191. #define EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE(_x) EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_FIELD((_x), TYPE)
  192. #define EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID(_x) EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_FIELD((_x), TID)
  193. #define EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_CODE(_x) EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_FIELD((_x), CODE)
  194. #define ACTIVATION_CONTEXT_TRUNCATED_TID_(_teb) (HandleToUlong((_teb)->ClientId.UniqueThread) & ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID_BIT_MASK)
  195. #define ACTIVATION_CONTEXT_TRUNCATED_TID() ACTIVATION_CONTEXT_TRUNCATED_TID_(NtCurrentTeb())
  196. PACTIVATION_CONTEXT
  197. RtlpMapSpecialValuesToBuiltInActivationContexts(
  198. PACTIVATION_CONTEXT ActivationContext
  199. )
  200. {
  201. if (ActivationContext == ACTCTX_EMPTY) {
  202. ActivationContext = &RtlpTheEmptyActivationContext;
  203. }
  204. return ActivationContext;
  205. }
  206. // Disable FPO optimization so that captured call stacks are more complete
  207. #if defined(_X86_)
  208. #pragma optimize( "y", off ) // disable FPO for consistent stack traces
  209. #endif
  210. NTSTATUS
  211. NTAPI
  212. RtlActivateActivationContext(
  213. ULONG Flags,
  214. PACTIVATION_CONTEXT ActivationContext,
  215. ULONG_PTR *CookieOut
  216. )
  217. {
  218. NTSTATUS Status = STATUS_INTERNAL_ERROR;
  219. ASSERT(Flags == 0);
  220. ASSERT(CookieOut != NULL);
  221. if (CookieOut != NULL)
  222. *CookieOut = INVALID_ACTIVATION_CONTEXT_ACTIVATION_COOKIE;
  223. if ((Flags != 0) || (CookieOut == NULL)) {
  224. Status = STATUS_INVALID_PARAMETER;
  225. goto Exit;
  226. }
  227. if (!NT_SUCCESS(Status = RtlActivateActivationContextEx(
  228. 0,
  229. NtCurrentTeb(),
  230. ActivationContext,
  231. CookieOut)))
  232. goto Exit;
  233. Status = STATUS_SUCCESS;
  234. Exit:
  235. return Status;
  236. }
  237. NTSTATUS
  238. NTAPI
  239. RtlActivateActivationContextEx(
  240. ULONG Flags,
  241. PTEB Teb,
  242. PACTIVATION_CONTEXT ActivationContext,
  243. ULONG_PTR *Cookie
  244. )
  245. {
  246. #if NT_SXS_PERF_COUNTERS_ENABLED
  247. ULONGLONG InitialCycleCount = RtlpGetCycleCount();
  248. #endif
  249. NTSTATUS Status = STATUS_SUCCESS;
  250. ULONG_PTR NewCookie = INVALID_ACTIVATION_CONTEXT_ACTIVATION_COOKIE;
  251. PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame;
  252. ULONG CapturedFrameCount, CapturedFrameHash;
  253. ASSERT(Cookie != NULL);
  254. if (Cookie != NULL)
  255. *Cookie = INVALID_ACTIVATION_CONTEXT_ACTIVATION_COOKIE;
  256. ASSERT((Flags & ~(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION)) == 0);
  257. ASSERT(Teb != NULL);
  258. ASSERT(ActivationContext != INVALID_HANDLE_VALUE);
  259. ActivationContext = RtlpMapSpecialValuesToBuiltInActivationContexts(ActivationContext);
  260. if (((Flags & ~(RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION)) != 0) ||
  261. (Teb == NULL) ||
  262. (ActivationContext == INVALID_HANDLE_VALUE) ||
  263. (Cookie == NULL)) {
  264. Status = STATUS_INVALID_PARAMETER;
  265. goto Exit;
  266. }
  267. Status = RtlpAllocateActivationContextStackFrame(0, Teb, &Frame);
  268. if (!NT_SUCCESS(Status))
  269. goto Exit;
  270. Frame->Frame.Flags = RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED;
  271. if (Flags & RTL_ACTIVATE_ACTIVATION_CONTEXT_EX_FLAG_RELEASE_ON_STACK_DEALLOCATION) {
  272. Frame->Frame.Flags |= RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE |
  273. RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION;
  274. RtlAddRefActivationContext(ActivationContext);
  275. }
  276. if (RtlpCaptureActivationContextActivationStacks)
  277. CapturedFrameCount = RtlCaptureStackBackTrace(2, NUMBER_OF(Frame->ActivationStackBackTrace), Frame->ActivationStackBackTrace, &CapturedFrameHash);
  278. else
  279. CapturedFrameCount = 0;
  280. while (CapturedFrameCount < NUMBER_OF(Frame->ActivationStackBackTrace))
  281. Frame->ActivationStackBackTrace[CapturedFrameCount++] = NULL;
  282. Frame->Frame.Previous = Teb->ActivationContextStack.ActiveFrame;
  283. Frame->Frame.ActivationContext = ActivationContext;
  284. NewCookie = MAKE_ACTIVATION_CONTEXT_ACTIVATION_COOKIE(ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_NORMAL, Teb, Teb->ActivationContextStack.NextCookieSequenceNumber);
  285. Teb->ActivationContextStack.NextCookieSequenceNumber++;
  286. Frame->Cookie = NewCookie;
  287. *Cookie = NewCookie;
  288. Teb->ActivationContextStack.ActiveFrame = &Frame->Frame;
  289. Status = STATUS_SUCCESS;
  290. Exit:
  291. #if NT_SXS_PERF_COUNTERS_ENABLED
  292. Teb->ActivationContextCounters.ActivationCycles += RtlpGetCycleCount() - InitialCycleCount;
  293. Teb->ActivationContextCounters.Activations++;
  294. #endif // NT_SXS_PERF_COUNTERS_ENABLED
  295. return Status;
  296. }
  297. #if defined(_X86_)
  298. #pragma optimize("", on)
  299. #endif
  300. VOID
  301. NTAPI
  302. RtlDeactivateActivationContext(
  303. ULONG Flags,
  304. ULONG_PTR Cookie
  305. )
  306. {
  307. #if NT_SXS_PERF_COUNTERS_ENABLED
  308. ULONGLONG InitialCycleCount = RtlpGetCycleCount();
  309. #endif // NT_SXS_PERF_COUNTERS_ENABLED
  310. PTEB Teb = NtCurrentTeb();
  311. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Frame;
  312. PRTL_ACTIVATION_CONTEXT_STACK_FRAME UnwindEndFrame;
  313. PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME HeapFrame = NULL;
  314. if ((Flags & ~(RTL_DEACTIVATE_ACTIVATION_CONTEXT_FLAG_FORCE_EARLY_DEACTIVATION)) != 0) {
  315. DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() called with invalid flags 0x%08lx\n", __FUNCTION__, Flags);
  316. RtlRaiseStatus(STATUS_INVALID_PARAMETER);
  317. }
  318. // Fast exit
  319. if (Cookie == INVALID_ACTIVATION_CONTEXT_ACTIVATION_COOKIE)
  320. return;
  321. if (EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE(Cookie) != ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TYPE_NORMAL) {
  322. DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() called with invalid cookie type 0x%08I64x\n", __FUNCTION__, Cookie);
  323. RtlRaiseStatus(STATUS_INVALID_PARAMETER);
  324. }
  325. if (EXTRACT_ACTIVATION_CONTEXT_ACTIVATION_COOKIE_TID(Cookie) != ACTIVATION_CONTEXT_TRUNCATED_TID()) {
  326. DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_ERROR_LEVEL, "SXS: %s() called with invalid cookie tid 0x%08I64x - should be %08lx\n", __FUNCTION__, Cookie, ACTIVATION_CONTEXT_TRUNCATED_TID());
  327. RtlRaiseStatus(STATUS_INVALID_PARAMETER);
  328. }
  329. Frame = (PRTL_ACTIVATION_CONTEXT_STACK_FRAME) Teb->ActivationContextStack.ActiveFrame;
  330. // Do the "downcast", but don't use HeapFrame unless the RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED
  331. // flag is set...
  332. if (Frame != NULL) {
  333. HeapFrame = (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) ? CONTAINING_RECORD(Frame, RTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME, Frame) : NULL;
  334. }
  335. RTL_SOFT_ASSERT((Frame != NULL) && (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) && (HeapFrame->Cookie == Cookie));
  336. if (Frame != NULL)
  337. {
  338. if (((Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) == 0) ||
  339. (HeapFrame->Cookie != Cookie))
  340. {
  341. ULONG InterveningFrameCount = 0;
  342. // The cookie wasn't current. Let's see if we can figure out what frame it was for...
  343. PRTL_ACTIVATION_CONTEXT_STACK_FRAME CandidateFrame = Frame->Previous;
  344. PRTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME CandidateHeapFrame =
  345. (CandidateFrame != NULL) ?
  346. (CandidateFrame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) ?
  347. CONTAINING_RECORD(CandidateFrame, RTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME, Frame) :
  348. NULL :
  349. NULL;
  350. while ((CandidateFrame != NULL) &&
  351. ((CandidateHeapFrame == NULL) ||
  352. (CandidateHeapFrame->Cookie != Cookie))) {
  353. InterveningFrameCount++;
  354. CandidateFrame = CandidateFrame->Previous;
  355. CandidateHeapFrame =
  356. (CandidateFrame != NULL) ?
  357. (CandidateFrame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) ?
  358. CONTAINING_RECORD(CandidateFrame, RTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME, Frame) :
  359. NULL :
  360. NULL;
  361. }
  362. RTL_SOFT_ASSERT(CandidateFrame != NULL);
  363. if (CandidateFrame == NULL) {
  364. RtlRaiseStatus(STATUS_SXS_INVALID_DEACTIVATION);
  365. } else {
  366. // Otherwise someone left some dirt around.
  367. EXCEPTION_RECORD ExceptionRecord;
  368. ExceptionRecord.ExceptionRecord = NULL;
  369. ExceptionRecord.NumberParameters = 3;
  370. ExceptionRecord.ExceptionInformation[0] = InterveningFrameCount;
  371. ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR) CandidateFrame;
  372. ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR) Teb->ActivationContextStack.ActiveFrame;
  373. ExceptionRecord.ExceptionCode = STATUS_SXS_EARLY_DEACTIVATION;
  374. ExceptionRecord.ExceptionFlags = 0; // this exception *is* continuable since we can actually put the activation stack into a reasonable state
  375. RtlRaiseException(&ExceptionRecord);
  376. // If they continue the exception, just do the unwinds.
  377. UnwindEndFrame = CandidateFrame->Previous;
  378. }
  379. } else
  380. UnwindEndFrame = Frame->Previous;
  381. do {
  382. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Previous = Frame->Previous;
  383. // This is a weird one. A no-deactivate frame is typically only used to propogate
  384. // active activation context state to a newly created thread. As such, it'll always
  385. // be the topmost frame... thus how did we come to decide to deactivate it?
  386. ASSERTMSG(
  387. "Unwinding through a no-deactivate frame",
  388. !(Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NO_DEACTIVATE));
  389. if (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION) {
  390. RtlReleaseActivationContext(Frame->ActivationContext);
  391. }
  392. if (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) {
  393. RtlpFreeActivationContextStackFrame(CONTAINING_RECORD(Frame, RTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME, Frame));
  394. }
  395. Frame = Previous;
  396. } while (Frame != UnwindEndFrame);
  397. Teb->ActivationContextStack.ActiveFrame = UnwindEndFrame;
  398. }
  399. #if NT_SXS_PERF_COUNTERS_ENABLED
  400. Teb->ActivationContextCounters.DeactivationCycles += RtlpGetCycleCount() - InitialCycleCount;
  401. Teb->ActivationContextCounters.Deactivations++;
  402. #endif
  403. }
  404. VOID
  405. RtlActivateActivationContextUnsafeFast(
  406. PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame,
  407. PACTIVATION_CONTEXT ActivationContext
  408. )
  409. {
  410. const PTEB Teb = NtCurrentTeb();
  411. const PRTL_ACTIVATION_CONTEXT_STACK_FRAME pStackFrame =
  412. (PRTL_ACTIVATION_CONTEXT_STACK_FRAME)Teb->ActivationContextStack.ActiveFrame;
  413. ASSERT(Frame->Format == RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER);
  414. ASSERT(Frame->Size >= sizeof(RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME));
  415. if ( ( ( ( pStackFrame == NULL ) && ( ActivationContext == NULL ) ) ||
  416. ( pStackFrame && ( pStackFrame->ActivationContext == ActivationContext ) ) )
  417. && !RtlpNotAllowingMultipleActivation )
  418. {
  419. // this uses too much stack in stress
  420. //DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() Not really activating\n", __FUNCTION__ );
  421. Frame->Frame.Flags |= RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED;
  422. }
  423. else
  424. {
  425. // this uses too much stack in stress
  426. //DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() Really activating\n", __FUNCTION__ );
  427. Frame->Frame.Previous = Teb->ActivationContextStack.ActiveFrame;
  428. Frame->Frame.ActivationContext = ActivationContext;
  429. Frame->Frame.Flags = 0;
  430. Teb->ActivationContextStack.ActiveFrame = &Frame->Frame;
  431. }
  432. }
  433. VOID
  434. RtlDeactivateActivationContextUnsafeFast(
  435. PRTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame
  436. )
  437. {
  438. const PTEB Teb = NtCurrentTeb();
  439. //
  440. // Was this "not really activated" above (AppCompat problem) from above?
  441. //
  442. if ( !RtlpNotAllowingMultipleActivation &&
  443. ( ( Frame->Frame.Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_NOT_REALLY_ACTIVATED ) != 0 ) )
  444. {
  445. return;
  446. }
  447. // Make sure that the deactivation matches. If it does not (the exceptional
  448. // condition) we'll throw an exception to make people deal with their
  449. // coding errors.
  450. else if (Teb->ActivationContextStack.ActiveFrame != &Frame->Frame)
  451. {
  452. EXCEPTION_RECORD ExceptionRecord;
  453. ULONG InterveningFrameCount = 0;
  454. // What's the deal? Look to see if we're further up the stack.
  455. // Actually, what we'll do is see if we can find our parent up the stack.
  456. // This will also handle the double-deactivation case and let us continue
  457. // nicely.
  458. PRTL_ACTIVATION_CONTEXT_STACK_FRAME SearchFrame = Teb->ActivationContextStack.ActiveFrame;
  459. const PRTL_ACTIVATION_CONTEXT_STACK_FRAME Previous = Frame->Frame.Previous;
  460. DbgPrintEx(DPFLTR_SXS_ID, DPFLTR_TRACE_LEVEL, "SXS: %s() Active frame is not the frame being deactivated %p != %p\n",
  461. __FUNCTION__,
  462. Teb->ActivationContextStack.ActiveFrame,
  463. &Frame->Frame);
  464. while ((SearchFrame != NULL) && (SearchFrame != Previous)) {
  465. InterveningFrameCount++;
  466. SearchFrame = SearchFrame->Previous;
  467. }
  468. ExceptionRecord.ExceptionRecord = NULL;
  469. ExceptionRecord.NumberParameters = 3;
  470. ExceptionRecord.ExceptionInformation[0] = InterveningFrameCount;
  471. ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR) &Frame->Frame;
  472. ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR) Teb->ActivationContextStack.ActiveFrame;
  473. if (SearchFrame != NULL) {
  474. // We're there. That's actually good; it just probably means that a function that our caller called
  475. // activated an activation context and forgot to deactivate. Throw the exception and if it's continued,
  476. // we're good to go.
  477. if (InterveningFrameCount == 0) {
  478. // Wow, the frame-to-deactivate's previous is the active one. It must be that the caller
  479. // already deactivated and is now deactivating again.
  480. ExceptionRecord.ExceptionCode = STATUS_SXS_MULTIPLE_DEACTIVATION;
  481. } else {
  482. // Otherwise someone left some dirt around.
  483. ExceptionRecord.ExceptionCode = STATUS_SXS_EARLY_DEACTIVATION;
  484. }
  485. ExceptionRecord.ExceptionFlags = 0; // this exception *is* continuable since we can actually put the activation stack into a reasonable state
  486. } else {
  487. // It wasn't there. It's almost certainly the wrong thing to try to set this
  488. ExceptionRecord.ExceptionCode = STATUS_SXS_INVALID_DEACTIVATION;
  489. ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; // this exception is NOT continuable
  490. }
  491. RtlRaiseException(&ExceptionRecord);
  492. }
  493. Teb->ActivationContextStack.ActiveFrame = Frame->Frame.Previous;
  494. }
  495. NTSTATUS
  496. NTAPI
  497. RtlGetActiveActivationContext(
  498. PACTIVATION_CONTEXT *ActivationContext
  499. )
  500. {
  501. NTSTATUS Status = STATUS_SUCCESS;
  502. PTEB Teb = NULL;
  503. PACTIVATION_CONTEXT_STACK Stack = NULL;
  504. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Frame = NULL;
  505. if (ActivationContext != NULL)
  506. *ActivationContext = NULL;
  507. if (ActivationContext == NULL) {
  508. Status = STATUS_INVALID_PARAMETER;
  509. goto Exit;
  510. }
  511. Teb = NtCurrentTeb();
  512. Frame = (PRTL_ACTIVATION_CONTEXT_STACK_FRAME) Teb->ActivationContextStack.ActiveFrame;
  513. if (Frame != NULL) {
  514. RtlAddRefActivationContext(Frame->ActivationContext);
  515. *ActivationContext = Frame->ActivationContext;
  516. }
  517. Status = STATUS_SUCCESS;
  518. Exit:
  519. return Status;
  520. }
  521. VOID
  522. NTAPI
  523. RtlFreeThreadActivationContextStack(
  524. VOID
  525. )
  526. {
  527. PTEB Teb = NtCurrentTeb();
  528. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Frame = (PRTL_ACTIVATION_CONTEXT_STACK_FRAME) Teb->ActivationContextStack.ActiveFrame;
  529. while (Frame != NULL) {
  530. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Previous = Frame->Previous;
  531. // Release any lingering frames. The notable case when this happens is when a thread that
  532. // has a non-default activation context active creates another thread which inherits the
  533. // first thread's activation context, adding a reference to the activation context. When
  534. // the new thread eventually dies, that initial frame is still active.
  535. if (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_RELEASE_ON_DEACTIVATION) {
  536. RtlReleaseActivationContext(Frame->ActivationContext);
  537. }
  538. if (Frame->Flags & RTL_ACTIVATION_CONTEXT_STACK_FRAME_FLAG_HEAP_ALLOCATED) {
  539. RtlpFreeActivationContextStackFrame(CONTAINING_RECORD(Frame, RTL_HEAP_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME, Frame));
  540. }
  541. Frame = Previous;
  542. }
  543. Teb->ActivationContextStack.ActiveFrame = NULL;
  544. }
  545. BOOLEAN
  546. NTAPI
  547. RtlIsActivationContextActive(
  548. PACTIVATION_CONTEXT ActivationContext
  549. )
  550. {
  551. PTEB Teb = NtCurrentTeb();
  552. PRTL_ACTIVATION_CONTEXT_STACK_FRAME Frame = (PRTL_ACTIVATION_CONTEXT_STACK_FRAME) Teb->ActivationContextStack.ActiveFrame;
  553. while (Frame != NULL) {
  554. if (Frame->ActivationContext == ActivationContext) {
  555. return TRUE;
  556. }
  557. Frame = Frame->Previous;
  558. }
  559. return FALSE;
  560. }