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.

363 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sxsappctx.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. #include <ntos.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <sxstypes.h>
  16. #include "sxsp.h"
  17. typedef const void *PCVOID;
  18. NTSTATUS
  19. RtlpValidateActivationContextData(
  20. IN ULONG Flags,
  21. IN PCACTIVATION_CONTEXT_DATA Data,
  22. IN SIZE_T BufferSize OPTIONAL
  23. )
  24. {
  25. NTSTATUS Status = STATUS_SUCCESS;
  26. PCACTIVATION_CONTEXT_DATA_TOC_HEADER TocHeader;
  27. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
  28. (Flags);
  29. if ((Data->Magic != ACTIVATION_CONTEXT_DATA_MAGIC) ||
  30. (Data->FormatVersion != ACTIVATION_CONTEXT_DATA_FORMAT_WHISTLER) ||
  31. ((BufferSize != 0) &&
  32. (BufferSize < Data->TotalSize)))
  33. {
  34. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  35. goto Exit;
  36. }
  37. // Check required elements...
  38. if (Data->DefaultTocOffset == 0) {
  39. DbgPrintEx(
  40. DPFLTR_SXS_ID,
  41. DPFLTR_ERROR_LEVEL,
  42. "SXS: Warning: Activation context data at %p missing default TOC\n", Data);
  43. }
  44. // How can we not have an assembly roster?
  45. if (Data->AssemblyRosterOffset == 0) {
  46. DbgPrintEx(
  47. DPFLTR_SXS_ID,
  48. DPFLTR_ERROR_LEVEL,
  49. "SXS: Warning: Activation context data at %p lacks assembly roster\n", Data);
  50. }
  51. if (Data->DefaultTocOffset != 0) {
  52. if ((Data->DefaultTocOffset >= Data->TotalSize) ||
  53. ((Data->DefaultTocOffset + sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) > Data->TotalSize)) {
  54. DbgPrintEx(
  55. DPFLTR_SXS_ID,
  56. DPFLTR_ERROR_LEVEL,
  57. "SXS: Activation context data at %p has invalid TOC header offset\n", Data);
  58. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  59. goto Exit;
  60. }
  61. TocHeader = (PCACTIVATION_CONTEXT_DATA_TOC_HEADER) (((ULONG_PTR) Data) + Data->DefaultTocOffset);
  62. if (TocHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_TOC_HEADER)) {
  63. DbgPrintEx(
  64. DPFLTR_SXS_ID,
  65. DPFLTR_ERROR_LEVEL,
  66. "SXS: Activation context data at %p has TOC header too small (%lu)\n", Data, TocHeader->HeaderSize);
  67. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  68. goto Exit;
  69. }
  70. if ((TocHeader->FirstEntryOffset >= Data->TotalSize) ||
  71. ((TocHeader->FirstEntryOffset + (TocHeader->EntryCount * sizeof(ACTIVATION_CONTEXT_DATA_TOC_ENTRY))) > Data->TotalSize)) {
  72. DbgPrintEx(
  73. DPFLTR_SXS_ID,
  74. DPFLTR_ERROR_LEVEL,
  75. "SXS: Activation context data at %p has invalid TOC entry array offset\n", Data);
  76. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  77. goto Exit;
  78. }
  79. }
  80. // we should finish validating the rest of the structure...
  81. if ((Data->AssemblyRosterOffset >= Data->TotalSize) ||
  82. ((Data->AssemblyRosterOffset + sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) > Data->TotalSize)) {
  83. DbgPrintEx(
  84. DPFLTR_SXS_ID,
  85. DPFLTR_ERROR_LEVEL,
  86. "SXS: Activation context data at %p has invalid assembly roster offset\n", Data);
  87. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  88. goto Exit;
  89. }
  90. AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) Data) + Data->AssemblyRosterOffset);
  91. if (Data->AssemblyRosterOffset != 0) {
  92. if (AssemblyRosterHeader->HeaderSize < sizeof(ACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER)) {
  93. DbgPrintEx(
  94. DPFLTR_SXS_ID,
  95. DPFLTR_ERROR_LEVEL,
  96. "SXS: Activation context data at %p has assembly roster header too small (%lu)\n", Data, AssemblyRosterHeader->HeaderSize);
  97. Status = STATUS_SXS_INVALID_ACTCTXDATA_FORMAT;
  98. goto Exit;
  99. }
  100. }
  101. Status = STATUS_SUCCESS;
  102. Exit:
  103. return Status;
  104. }
  105. const ACTIVATION_CONTEXT_DATA RtlpTheEmptyActivationContextData =
  106. {
  107. ACTIVATION_CONTEXT_DATA_MAGIC,
  108. sizeof(ACTIVATION_CONTEXT_DATA), // header size
  109. ACTIVATION_CONTEXT_DATA_FORMAT_WHISTLER,
  110. sizeof(ACTIVATION_CONTEXT_DATA), // total size
  111. 0, // default toc offset
  112. 0, // extended toc offset
  113. 0 // assembly roster index
  114. };
  115. // this struct is not const, its ref count can change (oops, no, that's
  116. // no longer true, but leave it mutable for now to be safe)
  117. ACTIVATION_CONTEXT RtlpTheEmptyActivationContext =
  118. {
  119. MAXULONG, // ref count, pinned
  120. ACTIVATION_CONTEXT_NOT_HEAP_ALLOCATED, // flags
  121. (PVOID)&RtlpTheEmptyActivationContextData
  122. // the rest zeros and NULLs
  123. };
  124. NTSTATUS
  125. NTAPI
  126. RtlCreateActivationContext(
  127. IN ULONG Flags,
  128. IN PCACTIVATION_CONTEXT_DATA ActivationContextData,
  129. IN ULONG ExtraBytes,
  130. IN PACTIVATION_CONTEXT_NOTIFY_ROUTINE NotificationRoutine,
  131. IN PVOID NotificationContext,
  132. OUT PACTIVATION_CONTEXT *ActCtx
  133. )
  134. {
  135. PACTIVATION_CONTEXT NewActCtx = NULL;
  136. NTSTATUS Status = STATUS_SUCCESS;
  137. ULONG i;
  138. PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER AssemblyRosterHeader;
  139. BOOLEAN UninitializeStorageMapOnExit = FALSE;
  140. DbgPrintEx(
  141. DPFLTR_SXS_ID,
  142. DPFLTR_TRACE_LEVEL,
  143. "SXS: RtlCreateActivationContext() called with parameters:\n"
  144. " Flags = 0x%08lx\n"
  145. " ActivationContextData = %p\n"
  146. " ExtraBytes = %lu\n"
  147. " NotificationRoutine = %p\n"
  148. " NotificationContext = %p\n"
  149. " ActCtx = %p\n",
  150. Flags,
  151. ActivationContextData,
  152. ExtraBytes,
  153. NotificationRoutine,
  154. NotificationContext,
  155. ActCtx);
  156. RTLP_DISALLOW_THE_EMPTY_ACTIVATION_CONTEXT_DATA(ActivationContextData);
  157. if (ActCtx != NULL)
  158. *ActCtx = NULL;
  159. if ((Flags != 0) ||
  160. (ActivationContextData == NULL) ||
  161. (ExtraBytes > 65536) ||
  162. (ActCtx == NULL))
  163. {
  164. Status = STATUS_INVALID_PARAMETER;
  165. goto Exit;
  166. }
  167. // Make sure that the activation context data passes muster
  168. Status = RtlpValidateActivationContextData(0, ActivationContextData, 0);
  169. if (NT_ERROR(Status))
  170. goto Exit;
  171. NewActCtx = (PACTIVATION_CONTEXT) RtlAllocateHeap(
  172. RtlProcessHeap(),
  173. 0,
  174. sizeof(ACTIVATION_CONTEXT) + ExtraBytes);
  175. if (NewActCtx == NULL)
  176. {
  177. Status = STATUS_NO_MEMORY;
  178. goto Exit;
  179. }
  180. AssemblyRosterHeader = (PCACTIVATION_CONTEXT_DATA_ASSEMBLY_ROSTER_HEADER) (((ULONG_PTR) ActivationContextData) + ActivationContextData->AssemblyRosterOffset);
  181. Status = RtlpInitializeAssemblyStorageMap(
  182. &NewActCtx->StorageMap,
  183. AssemblyRosterHeader->EntryCount,
  184. (AssemblyRosterHeader->EntryCount > NUMBER_OF(NewActCtx->InlineStorageMapEntries)) ? NULL : NewActCtx->InlineStorageMapEntries);
  185. if (NT_ERROR(Status))
  186. goto Exit;
  187. UninitializeStorageMapOnExit = TRUE;
  188. NewActCtx->RefCount = 1;
  189. NewActCtx->Flags = 0;
  190. NewActCtx->ActivationContextData = (PVOID) ActivationContextData;
  191. NewActCtx->NotificationRoutine = NotificationRoutine;
  192. NewActCtx->NotificationContext = NotificationContext;
  193. for (i=0; i<NUMBER_OF(NewActCtx->SentNotifications); i++)
  194. NewActCtx->SentNotifications[i] = 0;
  195. for (i=0; i<NUMBER_OF(NewActCtx->DisabledNotifications); i++)
  196. NewActCtx->DisabledNotifications[i] = 0;
  197. *ActCtx = NewActCtx;
  198. NewActCtx = NULL;
  199. UninitializeStorageMapOnExit = FALSE;
  200. Status = STATUS_SUCCESS;
  201. Exit:
  202. if (NewActCtx != NULL) {
  203. if (UninitializeStorageMapOnExit) {
  204. RtlpUninitializeAssemblyStorageMap(&NewActCtx->StorageMap);
  205. }
  206. RtlFreeHeap(RtlProcessHeap(), 0, NewActCtx);
  207. }
  208. return Status;
  209. }
  210. VOID
  211. NTAPI
  212. RtlAddRefActivationContext(
  213. PACTIVATION_CONTEXT ActCtx
  214. )
  215. {
  216. if ((ActCtx != NULL) &&
  217. (!IS_SPECIAL_ACTCTX(ActCtx)) &&
  218. (ActCtx->RefCount != MAXULONG))
  219. {
  220. LONG NewRefCount = 0;
  221. ASSERT(ActCtx->RefCount != 0);
  222. NewRefCount = InterlockedIncrement(&ActCtx->RefCount);
  223. // Probably indicative of a reference leak that's wrapped the refcount;
  224. // other probable cause is several concurrent releases.
  225. ASSERT(NewRefCount != 0);
  226. }
  227. }
  228. VOID
  229. NTAPI
  230. RtlReleaseActivationContext(
  231. PACTIVATION_CONTEXT ActCtx
  232. )
  233. {
  234. if ((ActCtx != NULL) &&
  235. (!IS_SPECIAL_ACTCTX(ActCtx)) &&
  236. (ActCtx->RefCount != MAXULONG))
  237. {
  238. LONG NewRefCount = 0;
  239. ASSERT(ActCtx->RefCount != 0);
  240. NewRefCount = InterlockedDecrement(&ActCtx->RefCount);
  241. if (NewRefCount == 0)
  242. {
  243. if (ActCtx->NotificationRoutine != NULL)
  244. {
  245. // There's no need to check for the notification being disabled; destroy
  246. // notifications are sent only once, so if the notification routine is not
  247. // null, we can just call it.
  248. BOOLEAN DisableNotification = FALSE;
  249. (*(ActCtx->NotificationRoutine))(
  250. ACTIVATION_CONTEXT_NOTIFICATION_DESTROY,
  251. ActCtx,
  252. ActCtx->ActivationContextData,
  253. ActCtx->NotificationContext,
  254. NULL,
  255. &DisableNotification);
  256. }
  257. RtlpUninitializeAssemblyStorageMap(&ActCtx->StorageMap);
  258. //
  259. // This predates the MAXULONG refcount, maybe we can get rid of the the flag now?
  260. //
  261. if ((ActCtx->Flags & ACTIVATION_CONTEXT_NOT_HEAP_ALLOCATED) == 0) {
  262. RtlFreeHeap(RtlProcessHeap(), 0, ActCtx);
  263. }
  264. }
  265. }
  266. }
  267. NTSTATUS
  268. NTAPI
  269. RtlZombifyActivationContext(
  270. PACTIVATION_CONTEXT ActCtx
  271. )
  272. {
  273. NTSTATUS Status = STATUS_SUCCESS;
  274. if ((ActCtx == NULL) || IS_SPECIAL_ACTCTX(ActCtx))
  275. {
  276. Status = STATUS_INVALID_PARAMETER;
  277. goto Exit;
  278. }
  279. if ((ActCtx->Flags & ACTIVATION_CONTEXT_ZOMBIFIED) == 0)
  280. {
  281. if (ActCtx->NotificationRoutine != NULL)
  282. {
  283. // Since disable is sent only once, there's no need to check for
  284. // disabled notifications.
  285. BOOLEAN DisableNotification = FALSE;
  286. (*(ActCtx->NotificationRoutine))(
  287. ACTIVATION_CONTEXT_NOTIFICATION_ZOMBIFY,
  288. ActCtx,
  289. ActCtx->ActivationContextData,
  290. ActCtx->NotificationContext,
  291. NULL,
  292. &DisableNotification);
  293. }
  294. ActCtx->Flags |= ACTIVATION_CONTEXT_ZOMBIFIED;
  295. }
  296. Status = STATUS_SUCCESS;
  297. Exit:
  298. return Status;
  299. }