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.

2309 lines
68 KiB

  1. /*++
  2. Copyright (c) Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. critsect.c
  5. Abstract:
  6. This module implements verification functions for
  7. critical section interfaces.
  8. Author:
  9. Daniel Mihai (DMihai) 27-Mar-2001
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #include "verifier.h"
  14. #include "critsect.h"
  15. #include "support.h"
  16. #include "deadlock.h"
  17. #include "logging.h"
  18. //
  19. // Ntdll functions declarations.
  20. //
  21. VOID
  22. RtlpWaitForCriticalSection (
  23. IN PRTL_CRITICAL_SECTION CriticalSection
  24. );
  25. //
  26. // The root of our critical section splay tree, ordered by
  27. // the address of the critical sections.
  28. //
  29. PRTL_SPLAY_LINKS CritSectSplayRoot = NULL;
  30. //
  31. // Global lock protecting the access to our splay tree.
  32. //
  33. // N.B.
  34. //
  35. // WE CANNOT HOLD THIS LOCK AND CALL ANY API THAT WILL
  36. // TRY TRY TO AQUIRE ANOTHER LOCK (e.g. RtlAllocateHeap)
  37. // BECAUSE THE FUNCTIONS BELOW CAN BE CALLED WITH THAT OTHER
  38. // LOCK HELD BY ANOTHER THREAD AND WE WILL DEADLOCK.
  39. //
  40. RTL_CRITICAL_SECTION CriticalSectionLock;
  41. BOOL CriticalSectionLockInitialized = FALSE;
  42. NTSTATUS
  43. CritSectInitialize (
  44. VOID
  45. )
  46. {
  47. NTSTATUS Status = STATUS_SUCCESS;
  48. Status = RtlInitializeCriticalSectionAndSpinCount (&CriticalSectionLock,
  49. 0x80000000);
  50. if (NT_SUCCESS (Status)) {
  51. CriticalSectionLockInitialized = TRUE;
  52. }
  53. return Status;
  54. }
  55. VOID
  56. CritSectUninitialize (
  57. VOID
  58. )
  59. {
  60. if (CriticalSectionLockInitialized) {
  61. RtlDeleteCriticalSection (&CriticalSectionLock);
  62. CriticalSectionLockInitialized = FALSE;
  63. }
  64. }
  65. VOID
  66. AVrfpVerifyCriticalSectionOwner (
  67. volatile RTL_CRITICAL_SECTION *CriticalSection,
  68. BOOL VerifyCountOwnedByThread
  69. )
  70. {
  71. HANDLE CurrentThread;
  72. PAVRF_TLS_STRUCT TlsStruct;
  73. //
  74. // Verify that the CS is locked.
  75. //
  76. if (CriticalSection->LockCount < 0) {
  77. //
  78. // The CS is not locked
  79. //
  80. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  81. "critical section over-released or corrupted",
  82. CriticalSection, "Critical section address",
  83. CriticalSection->LockCount, "Lock count",
  84. 0, "Expected minimum lock count",
  85. CriticalSection->DebugInfo, "Critical section debug info address");
  86. }
  87. //
  88. // Verify that the current thread owns the CS.
  89. //
  90. CurrentThread = NtCurrentTeb()->ClientId.UniqueThread;
  91. if (CriticalSection->OwningThread != CurrentThread) {
  92. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  93. "invalid critical section owner thread",
  94. CriticalSection, "Critical section address",
  95. CriticalSection->OwningThread, "Owning thread",
  96. CurrentThread, "Expected owning thread",
  97. CriticalSection->DebugInfo, "Critical section debug info address");
  98. }
  99. //
  100. // Verify the recursion count.
  101. //
  102. // ntdll\ia64\critsect.s is using RecursionCount = 0 first time
  103. // the current thread is acquiring the CS.
  104. //
  105. // ntdll\i386\critsect.asm is using RecursionCount = 1 first time
  106. // the current thread is acquiring the CS.
  107. //
  108. #if defined(_IA64_)
  109. if (CriticalSection->RecursionCount < 0) {
  110. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  111. "invalid critical section recursion count",
  112. CriticalSection, "Critical section address",
  113. CriticalSection->RecursionCount, "Recursion count",
  114. 0, "Expected minimum recursion count",
  115. CriticalSection->DebugInfo, "Critical section debug info address");
  116. }
  117. #else //#if defined(_IA64_)
  118. if (CriticalSection->RecursionCount < 1) {
  119. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  120. "invalid critical section recursion count",
  121. CriticalSection, "Critical section address",
  122. CriticalSection->RecursionCount, "Recursion count",
  123. 1, "Expected minimum recursion count",
  124. CriticalSection->DebugInfo, "Critical section debug info address");
  125. }
  126. #endif //#if defined(_IA64_)
  127. if (VerifyCountOwnedByThread != FALSE) {
  128. //
  129. // Verify that the current thread owns at least one critical section.
  130. //
  131. TlsStruct = AVrfpGetVerifierTlsValue();
  132. if (TlsStruct != NULL && TlsStruct->CountOfOwnedCriticalSections <= 0) {
  133. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  134. "critical section over-released or corrupted",
  135. TlsStruct->CountOfOwnedCriticalSections, "Number of critical sections owned by curent thread.",
  136. NULL, "",
  137. NULL, "",
  138. NULL, "");
  139. }
  140. }
  141. }
  142. VOID
  143. AVrfpDumpCritSectTreeRecursion(
  144. PRTL_SPLAY_LINKS Root,
  145. ULONG RecursionLevel
  146. )
  147. {
  148. ULONG RecursionCount;
  149. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  150. for (RecursionCount = 0; RecursionCount < RecursionLevel; RecursionCount += 1) {
  151. DbgPrint (" ");
  152. }
  153. CritSectSplayNode = CONTAINING_RECORD (Root,
  154. CRITICAL_SECTION_SPLAY_NODE,
  155. SplayLinks);
  156. DbgPrint ("%p (CS = %p, DebugInfo = %p), left %p, right %p, parent %p\n",
  157. Root,
  158. CritSectSplayNode->CriticalSection,
  159. CritSectSplayNode->DebugInfo,
  160. Root->LeftChild,
  161. Root->RightChild,
  162. Root->Parent);
  163. if (Root->LeftChild != NULL) {
  164. AVrfpDumpCritSectTreeRecursion (Root->LeftChild,
  165. RecursionLevel + 1 );
  166. }
  167. if (Root->RightChild != NULL) {
  168. AVrfpDumpCritSectTreeRecursion (Root->RightChild,
  169. RecursionLevel + 1 );
  170. }
  171. }
  172. VOID
  173. AVrfpDumpCritSectTree(
  174. )
  175. {
  176. //
  177. // N.B.
  178. //
  179. // This code is dangerous because we are calling DbgPrint
  180. // with CriticalSectionLock held. If DbgPrint is using
  181. // the heap internally it might need the heap lock
  182. // which might be help by another thread waiting for CriticalSectionLock.
  183. // We are going to use this function only in desperate cases
  184. // for debugging verifier issues with the CS tree.
  185. //
  186. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) {
  187. AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock,
  188. FALSE);
  189. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_DUMP_TREE) != 0) {
  190. DbgPrint ("================================================\n"
  191. "Critical section tree root = %p\n",
  192. CritSectSplayRoot);
  193. if (CritSectSplayRoot != NULL) {
  194. AVrfpDumpCritSectTreeRecursion( CritSectSplayRoot,
  195. 0 );
  196. }
  197. DbgPrint ("================================================\n");
  198. }
  199. }
  200. }
  201. NTSTATUS
  202. AVrfpInsertCritSectInSplayTree (
  203. PRTL_CRITICAL_SECTION CriticalSection
  204. )
  205. {
  206. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  207. PCRITICAL_SECTION_SPLAY_NODE NewCritSectSplayNode;
  208. PRTL_SPLAY_LINKS Parent;
  209. NTSTATUS Status;
  210. ASSERT (CriticalSection->DebugInfo != NULL);
  211. Status = STATUS_SUCCESS;
  212. NewCritSectSplayNode = NULL;
  213. //
  214. // The caller must be the owner of the splay tree lock.
  215. //
  216. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) {
  217. AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock,
  218. FALSE);
  219. DbgPrint ("\n\nAVrfpInsertCritSectInSplayTree( %p )\n",
  220. CriticalSection);
  221. AVrfpDumpCritSectTree ();
  222. }
  223. //
  224. // Allocate a new node.
  225. //
  226. // N.B.
  227. //
  228. // We need to drop CriticalSectionLock while using the heap.
  229. // Otherwise we might deadlock. This also means that another thread
  230. // might come along and initialize this critical section again.
  231. // We don;t expect this to happen often and we will detect this
  232. // only later on, in ntdll!RtlCheckForOrphanedCriticalSections.
  233. //
  234. RtlLeaveCriticalSection (&CriticalSectionLock);
  235. try {
  236. NewCritSectSplayNode = AVrfpAllocate (sizeof (*NewCritSectSplayNode));
  237. }
  238. finally {
  239. RtlEnterCriticalSection (&CriticalSectionLock);
  240. }
  241. if (NewCritSectSplayNode == NULL) {
  242. Status = STATUS_NO_MEMORY;
  243. }
  244. else {
  245. //
  246. // Initialize the data members of the node structure.
  247. //
  248. NewCritSectSplayNode->CriticalSection = CriticalSection;
  249. NewCritSectSplayNode->DebugInfo = CriticalSection->DebugInfo;
  250. //
  251. // Insert the node in the tree.
  252. //
  253. ZeroMemory( &NewCritSectSplayNode->SplayLinks,
  254. sizeof(NewCritSectSplayNode->SplayLinks));
  255. //
  256. // If the tree is currently empty set the new node as root.
  257. //
  258. if (CritSectSplayRoot == NULL) {
  259. NewCritSectSplayNode->SplayLinks.Parent = &NewCritSectSplayNode->SplayLinks;
  260. CritSectSplayRoot = &NewCritSectSplayNode->SplayLinks;
  261. }
  262. else {
  263. //
  264. // Search for the right place to insert our CS in the tree.
  265. //
  266. Parent = CritSectSplayRoot;
  267. while (TRUE) {
  268. CritSectSplayNode = CONTAINING_RECORD (Parent,
  269. CRITICAL_SECTION_SPLAY_NODE,
  270. SplayLinks);
  271. if (CriticalSection < CritSectSplayNode->CriticalSection) {
  272. //
  273. // Starting address of the virtual address descriptor is less
  274. // than the parent starting virtual address.
  275. // Follow left child link if not null. Otherwise
  276. // return from the function - we didn't find the CS.
  277. //
  278. if (Parent->LeftChild) {
  279. Parent = Parent->LeftChild;
  280. }
  281. else {
  282. //
  283. // Insert the node here.
  284. //
  285. RtlInsertAsLeftChild (Parent,
  286. NewCritSectSplayNode);
  287. break;
  288. }
  289. }
  290. else {
  291. //
  292. // Starting address of the virtual address descriptor is greater
  293. // than the parent starting virtual address.
  294. // Follow right child link if not null. Otherwise
  295. // return from the function - we didn't find the CS.
  296. //
  297. if (Parent->RightChild) {
  298. Parent = Parent->RightChild;
  299. }
  300. else {
  301. //
  302. // Insert the node here.
  303. //
  304. RtlInsertAsRightChild (Parent,
  305. NewCritSectSplayNode);
  306. break;
  307. }
  308. }
  309. }
  310. CritSectSplayRoot = RtlSplay( CritSectSplayRoot );
  311. }
  312. }
  313. return Status;
  314. }
  315. PCRITICAL_SECTION_SPLAY_NODE
  316. AVrfpFindCritSectInSplayTree (
  317. PRTL_CRITICAL_SECTION CriticalSection
  318. )
  319. {
  320. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  321. PCRITICAL_SECTION_SPLAY_NODE FoundNode;
  322. PRTL_SPLAY_LINKS Parent;
  323. FoundNode = NULL;
  324. //
  325. // The caller must be the owner of the splay tree lock.
  326. //
  327. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) {
  328. AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock,
  329. FALSE);
  330. DbgPrint ("\n\nAVrfpFindCritSectInSplayTree( %p )\n",
  331. CriticalSection);
  332. AVrfpDumpCritSectTree ();
  333. }
  334. if (CritSectSplayRoot == NULL) {
  335. goto Done;
  336. }
  337. //
  338. // Search for our CS in the tree.
  339. //
  340. Parent = CritSectSplayRoot;
  341. while (TRUE) {
  342. CritSectSplayNode = CONTAINING_RECORD (Parent,
  343. CRITICAL_SECTION_SPLAY_NODE,
  344. SplayLinks);
  345. if (CriticalSection == CritSectSplayNode->CriticalSection) {
  346. //
  347. // Found it.
  348. //
  349. FoundNode = CritSectSplayNode;
  350. break;
  351. }
  352. else if (CriticalSection < CritSectSplayNode->CriticalSection) {
  353. //
  354. // Starting address of the virtual address descriptor is less
  355. // than the parent starting virtual address.
  356. // Follow left child link if not null. Otherwise
  357. // return from the function - we didn't find the CS.
  358. //
  359. if (Parent->LeftChild) {
  360. Parent = Parent->LeftChild;
  361. }
  362. else {
  363. break;
  364. }
  365. }
  366. else {
  367. //
  368. // Starting address of the virtual address descriptor is greater
  369. // than the parent starting virtual address.
  370. // Follow right child link if not null. Otherwise
  371. // return from the function - we didn't find the CS.
  372. //
  373. if (Parent->RightChild) {
  374. Parent = Parent->RightChild;
  375. }
  376. else {
  377. break;
  378. }
  379. }
  380. }
  381. Done:
  382. return FoundNode;
  383. }
  384. VOID
  385. AVrfpDeleteCritSectFromSplayTree (
  386. PRTL_CRITICAL_SECTION CriticalSection
  387. )
  388. {
  389. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  390. //
  391. // The caller must be the owner of the splay tree lock.
  392. //
  393. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_VERIFIER) != 0) {
  394. AVrfpVerifyCriticalSectionOwner (&CriticalSectionLock,
  395. FALSE);
  396. DbgPrint ("\n\nAVrfpDeleteCritSectFromSplayTree( %p )\n",
  397. CriticalSection);
  398. AVrfpDumpCritSectTree ();
  399. }
  400. //
  401. // Find the critical section in the tree and delete it.
  402. //
  403. CritSectSplayNode = AVrfpFindCritSectInSplayTree (CriticalSection);
  404. if (CritSectSplayNode != NULL) {
  405. CritSectSplayRoot = RtlDelete (&CritSectSplayNode->SplayLinks);
  406. // N.B.
  407. //
  408. // We need to drop CriticalSectionLock while using the heap.
  409. // Otherwise we might deadlock. This also means that another thread
  410. // might come along and initialize this critical section again.
  411. // We don;t expect this to happen often and we will detect this
  412. // only later on, in ntdll!RtlCheckForOrphanedCriticalSections.
  413. //
  414. RtlLeaveCriticalSection (&CriticalSectionLock);
  415. try {
  416. AVrfpFree (CritSectSplayNode);
  417. }
  418. finally {
  419. RtlEnterCriticalSection (&CriticalSectionLock );
  420. }
  421. }
  422. else {
  423. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  424. RtlDllShutdownInProgress() == FALSE ) {
  425. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  426. "critical section not initialized",
  427. CriticalSection, "Critical section address",
  428. CriticalSection->DebugInfo, "Critical section debug info address",
  429. NULL, "",
  430. NULL, "");
  431. }
  432. }
  433. }
  434. PCRITICAL_SECTION_SPLAY_NODE
  435. AVrfpVerifyInitializedCriticalSection (
  436. volatile RTL_CRITICAL_SECTION *CriticalSection
  437. )
  438. {
  439. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  440. CritSectSplayNode = NULL;
  441. //
  442. // Sanity test for DebugInfo.
  443. //
  444. if (CriticalSection->DebugInfo == NULL) {
  445. //
  446. // This CS is not initialized.
  447. //
  448. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  449. "critical section not initialized",
  450. CriticalSection, "Critical section address",
  451. CriticalSection->DebugInfo, "Critical section debug info address",
  452. NULL, "",
  453. NULL, "");
  454. }
  455. else if (CriticalSection != NtCurrentPeb()->LoaderLock) {
  456. //
  457. // The loader lock is not in our tree because it is initialized in ntdll
  458. // but is exposed via the pointer in the PEB so various pieces of code
  459. // are (ab)using it...
  460. //
  461. //
  462. // Grab the CS splay tree lock.
  463. //
  464. RtlEnterCriticalSection (&CriticalSectionLock );
  465. try {
  466. //
  467. // If the CS was initialized it should be in our tree.
  468. //
  469. CritSectSplayNode = AVrfpFindCritSectInSplayTree ((PRTL_CRITICAL_SECTION)CriticalSection);
  470. if (CritSectSplayNode == NULL) {
  471. //
  472. // This CS is not initialized.
  473. //
  474. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_NOT_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  475. "critical section not initialized",
  476. CriticalSection, "Critical section address",
  477. CriticalSection->DebugInfo, "Critical section debug info address",
  478. NULL, "",
  479. NULL, "");
  480. }
  481. }
  482. finally {
  483. //
  484. // Release the CS splay tree lock.
  485. //
  486. RtlLeaveCriticalSection( &CriticalSectionLock );
  487. }
  488. }
  489. return CritSectSplayNode;
  490. }
  491. VOID
  492. AVrfpVerifyInitializedCriticalSection2 (
  493. volatile RTL_CRITICAL_SECTION *CriticalSection
  494. )
  495. {
  496. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  497. RtlDllShutdownInProgress() == FALSE ) {
  498. //
  499. // Grab the CS splay tree lock.
  500. //
  501. RtlEnterCriticalSection( &CriticalSectionLock );
  502. try {
  503. //
  504. // Verify that the CS was initialized.
  505. //
  506. AVrfpVerifyInitializedCriticalSection (CriticalSection);
  507. }
  508. finally {
  509. //
  510. // Release the CS splay tree lock.
  511. //
  512. RtlLeaveCriticalSection( &CriticalSectionLock );
  513. }
  514. }
  515. }
  516. VOID
  517. AVrfpVerifyNoWaitersCriticalSection (
  518. volatile RTL_CRITICAL_SECTION *CriticalSection
  519. )
  520. {
  521. PAVRF_TLS_STRUCT TlsStruct;
  522. PTEB Teb;
  523. Teb = NtCurrentTeb();
  524. //
  525. // Verify that no thread owns or waits for this CS or
  526. // the owner is the current thread.
  527. //
  528. // ntdll\ia64\critsect.s is using RecursionCount = 0 first time
  529. // the current thread is acquiring the CS.
  530. //
  531. // ntdll\i386\critsect.asm is using RecursionCount = 1 first time
  532. // the current thread is acquiring the CS.
  533. //
  534. if (CriticalSection->LockCount != -1)
  535. {
  536. if (CriticalSection->OwningThread != Teb->ClientId.UniqueThread ||
  537. #if defined(_WIN64)
  538. CriticalSection->RecursionCount < 0) {
  539. #else
  540. CriticalSection->RecursionCount < 1) {
  541. #endif //#if defined(_IA64_)
  542. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_LOCK_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  543. "deleting critical section with invalid lock count",
  544. CriticalSection, "Critical section address",
  545. CriticalSection->LockCount, "Lock count",
  546. -1, "Expected lock count",
  547. CriticalSection->OwningThread, "Owning thread");
  548. }
  549. else
  550. {
  551. //
  552. // Deleting CS currently owned by the current thread.
  553. // Unfortunately we have to allow this because various
  554. // components have beein doing it for years.
  555. //
  556. AVrfpIncrementOwnedCriticalSections (-1);
  557. //
  558. // For debugging purposes, keep the address of the critical section deleted while
  559. // its LockCount was incorrect. Teb->CountOfOwnedCriticalSections might be left > 0
  560. // although no critical section is owned by the current thread in this case.
  561. //
  562. TlsStruct = AVrfpGetVerifierTlsValue();
  563. if (TlsStruct != NULL) {
  564. TlsStruct->IgnoredIncorrectDeleteCS = (PRTL_CRITICAL_SECTION)CriticalSection;
  565. }
  566. }
  567. }
  568. }
  569. VOID
  570. AVrfpFreeMemLockChecks (
  571. VERIFIER_DLL_FREEMEM_TYPE FreeMemType,
  572. PVOID StartAddress,
  573. SIZE_T RegionSize,
  574. PWSTR UnloadedDllName
  575. )
  576. {
  577. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  578. PRTL_SPLAY_LINKS Parent;
  579. PVOID TraceAddress = NULL;
  580. //
  581. // Check for leaked critical sections in this memory range.
  582. //
  583. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  584. RtlDllShutdownInProgress() == FALSE ) {
  585. //
  586. // Grab the CS tree lock.
  587. //
  588. RtlEnterCriticalSection( &CriticalSectionLock );
  589. //
  590. // Search the CS tree.
  591. //
  592. try {
  593. if (CritSectSplayRoot != NULL) {
  594. //
  595. // Look in the splay tree for any critical sections
  596. // that might live in the memory range that isbeing deleted.
  597. //
  598. Parent = CritSectSplayRoot;
  599. while (TRUE) {
  600. CritSectSplayNode = CONTAINING_RECORD (Parent,
  601. CRITICAL_SECTION_SPLAY_NODE,
  602. SplayLinks);
  603. if ( (PCHAR)CritSectSplayNode->CriticalSection >= (PCHAR)StartAddress &&
  604. (PCHAR)CritSectSplayNode->CriticalSection < (PCHAR)StartAddress + RegionSize) {
  605. //
  606. // Found a CS that is about to be leaked.
  607. //
  608. if (AVrfpGetStackTraceAddress != NULL) {
  609. TraceAddress = AVrfpGetStackTraceAddress (
  610. CritSectSplayNode->DebugInfo->CreatorBackTraceIndex);
  611. }
  612. else {
  613. TraceAddress = NULL;
  614. }
  615. switch (FreeMemType) {
  616. case VerifierFreeMemTypeFreeHeap:
  617. //
  618. // We are releasing a heap block that contains this CS
  619. //
  620. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_HEAP | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  621. "releasing heap allocation containing active critical section",
  622. CritSectSplayNode->CriticalSection, "Critical section address",
  623. TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.",
  624. StartAddress, "Heap block address",
  625. RegionSize, "Heap block size" );
  626. break;
  627. case VerifierFreeMemTypeVirtualFree:
  628. //
  629. // We are releasing a virtual memory that contains this CS
  630. //
  631. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  632. "releasing virtual memory containing active critical section",
  633. CritSectSplayNode->CriticalSection, "Critical section address",
  634. TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.",
  635. StartAddress, "Memory block address",
  636. RegionSize, "Memory block size");
  637. break;
  638. case VerifierFreeMemTypeUnloadDll:
  639. ASSERT (UnloadedDllName != NULL);
  640. //
  641. // We are unloading a DLL that contained this CS
  642. //
  643. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_UNLOADED_DLL | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  644. "unloading dll containing active critical section",
  645. CritSectSplayNode->CriticalSection, "Critical section address",
  646. TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.",
  647. UnloadedDllName, "DLL name address. Use du to dump it.",
  648. StartAddress, "DLL base address");
  649. break;
  650. case VerifierFreeMemTypeUnmap:
  651. //
  652. // We are unmapping memory that contains this CS
  653. //
  654. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_IN_FREED_MEMORY | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  655. "Unmapping memory region containing active critical section",
  656. CritSectSplayNode->CriticalSection, "Critical section address",
  657. TraceAddress, "Initialization stack trace. Use dds to dump it if non-NULL.",
  658. StartAddress, "Memory block address",
  659. RegionSize, "Memory block size" );
  660. break;
  661. default:
  662. ASSERT (FALSE);
  663. }
  664. //
  665. // Try to find other leaked critical sections only
  666. // with address greater than the current one
  667. // (only in the right subtree).
  668. //
  669. if (Parent->RightChild) {
  670. Parent = Parent->RightChild;
  671. }
  672. else {
  673. break;
  674. }
  675. }
  676. else if ((PCHAR)StartAddress < (PCHAR)CritSectSplayNode->CriticalSection) {
  677. //
  678. // Starting address of the virtual address descriptor is less
  679. // than the parent starting virtual address.
  680. // Follow left child link if not null. Otherwise
  681. // return from the function - we didn't find the CS.
  682. //
  683. if (Parent->LeftChild) {
  684. Parent = Parent->LeftChild;
  685. }
  686. else {
  687. break;
  688. }
  689. }
  690. else {
  691. //
  692. // Starting address of the virtual address descriptor is greater
  693. // than the parent starting virtual address.
  694. // Follow right child link if not null. Otherwise
  695. // return from the function - we didn't find the CS.
  696. //
  697. if (Parent->RightChild) {
  698. Parent = Parent->RightChild;
  699. }
  700. else {
  701. break;
  702. }
  703. }
  704. }
  705. }
  706. }
  707. finally {
  708. //
  709. // Release the CS splay tree lock.
  710. //
  711. RtlLeaveCriticalSection( &CriticalSectionLock );
  712. }
  713. }
  714. }
  715. #if defined(_X86_)
  716. #pragma optimize("y", off) // disable FPO
  717. #endif
  718. //NTSYSAPI
  719. BOOL
  720. NTAPI
  721. AVrfpRtlTryEnterCriticalSection(
  722. PRTL_CRITICAL_SECTION CriticalSection
  723. )
  724. {
  725. BOOL Result;
  726. HANDLE CurrentThread;
  727. LONG LockCount;
  728. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  729. PTEB Teb;
  730. BOOL AlreadyOwner;
  731. Teb = NtCurrentTeb();
  732. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  733. RtlDllShutdownInProgress() == FALSE ) {
  734. CurrentThread = Teb->ClientId.UniqueThread;
  735. //
  736. // Verify that the CS was initialized.
  737. //
  738. CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection);
  739. if (CritSectSplayNode != NULL)
  740. {
  741. InterlockedExchangePointer (&CritSectSplayNode->TryEnterThread,
  742. (PVOID)CurrentThread);
  743. }
  744. //
  745. // The TryEnterCriticalSection algorithm starts here.
  746. //
  747. LockCount = InterlockedCompareExchange( &CriticalSection->LockCount,
  748. 0,
  749. -1 );
  750. if (LockCount == -1) {
  751. //
  752. // The CS was unowned and we just acquired it
  753. //
  754. //
  755. // Sanity test for the OwningThread.
  756. //
  757. if (CriticalSection->OwningThread != 0) {
  758. //
  759. // The loader lock gets handled differently, so don't assert on it.
  760. //
  761. if (CriticalSection != NtCurrentPeb()->LoaderLock ||
  762. CriticalSection->OwningThread != CurrentThread) {
  763. //
  764. // OwningThread should have been 0.
  765. //
  766. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  767. "invalid critical section owner thread",
  768. CriticalSection, "Critical section address",
  769. CriticalSection->OwningThread, "Owning thread",
  770. 0, "Expected owning thread",
  771. CriticalSection->DebugInfo, "Critical section debug info address");
  772. }
  773. }
  774. //
  775. // Sanity test for the RecursionCount.
  776. //
  777. if (CriticalSection->RecursionCount != 0) {
  778. //
  779. // The loader lock gets handled differently, so don't assert on it.
  780. //
  781. if (CriticalSection != NtCurrentPeb()->LoaderLock) {
  782. //
  783. // RecursionCount should have been 0.
  784. //
  785. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  786. "invalid critical section recursion count",
  787. CriticalSection, "Critical section address",
  788. CriticalSection->RecursionCount, "Recursion count",
  789. 0, "Expected recursion count",
  790. CriticalSection->DebugInfo, "Critical section debug info address");
  791. }
  792. }
  793. //
  794. // Set the CS owner
  795. //
  796. CriticalSection->OwningThread = CurrentThread;
  797. //
  798. // Set the recursion count
  799. //
  800. // ntdll\ia64\critsect.s is using RecursionCount = 0 first time
  801. // the current thread is acquiring the critical section.
  802. //
  803. // ntdll\i386\critsect.asm is using RecursionCount = 1 first time
  804. // the current thread is acquiring the critical section.
  805. //
  806. #if defined(_IA64_)
  807. CriticalSection->RecursionCount = 0;
  808. #else //#if defined(_IA64_)
  809. CriticalSection->RecursionCount = 1;
  810. #endif
  811. AVrfpIncrementOwnedCriticalSections (1);
  812. //
  813. // We are updating this counter on all platforms,
  814. // unlike the ntdll code that does this only on x86 chk.
  815. // We need the updated counter in the TEB to speed up
  816. // ntdll!RtlCheckHeldCriticalSections.
  817. //
  818. Teb->CountOfOwnedCriticalSections += 1;
  819. //
  820. // All done, CriticalSection is owned by the current thread.
  821. //
  822. Result = TRUE;
  823. }
  824. else {
  825. //
  826. // The CS is currently owned by the current or another thread.
  827. //
  828. if (CriticalSection->OwningThread == CurrentThread) {
  829. //
  830. // The current thread is already the owner.
  831. //
  832. //
  833. // Interlock increment the LockCount, and increment the RecursionCount.
  834. //
  835. InterlockedIncrement (&CriticalSection->LockCount);
  836. CriticalSection->RecursionCount += 1;
  837. //
  838. // All done, CriticalSection was already owned by
  839. // the current thread and we have just incremented the RecursionCount.
  840. //
  841. Result = TRUE;
  842. }
  843. else {
  844. //
  845. // Another thread is the owner of this CS.
  846. //
  847. Result = FALSE;
  848. }
  849. }
  850. }
  851. else {
  852. //
  853. // The CS verifier is not enabled
  854. //
  855. Result = RtlTryEnterCriticalSection (CriticalSection);
  856. if (Result != FALSE) {
  857. #if defined(_IA64_)
  858. AlreadyOwner = (CriticalSection->RecursionCount > 0);
  859. #else
  860. AlreadyOwner = (CriticalSection->RecursionCount > 1);
  861. #endif //#if defined(_IA64_)
  862. if (AlreadyOwner == FALSE) {
  863. AVrfpIncrementOwnedCriticalSections (1);
  864. #if !DBG || !defined (_X86_)
  865. //
  866. // We are updating this counter on all platforms,
  867. // unlike the ntdll code that does this only on x86 chk.
  868. // We need the updated counter in the TEB to speed up
  869. // ntdll!RtlCheckHeldCriticalSections.
  870. //
  871. Teb->CountOfOwnedCriticalSections += 1;
  872. #endif //#if !DBG || !defined (_X86_)
  873. }
  874. }
  875. }
  876. if (Result != FALSE) {
  877. //
  878. // Tell deadlock verifier that the lock has been acquired.
  879. //
  880. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
  881. AVrfDeadlockResourceAcquire (CriticalSection,
  882. _ReturnAddress(),
  883. TRUE);
  884. }
  885. //
  886. // We will introduce a random delay
  887. // in order to randomize the timings in the process.
  888. //
  889. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_RACE_CHECKS)) {
  890. AVrfpCreateRandomDelay ();
  891. }
  892. }
  893. return Result;
  894. }
  895. #if defined(_X86_)
  896. #pragma optimize("y", off) // disable FPO
  897. #endif
  898. //NTSYSAPI
  899. NTSTATUS
  900. NTAPI
  901. AVrfpRtlEnterCriticalSection(
  902. volatile RTL_CRITICAL_SECTION *CriticalSection
  903. )
  904. {
  905. NTSTATUS Status;
  906. HANDLE CurrentThread;
  907. LONG LockCount;
  908. ULONG_PTR SpinCount;
  909. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  910. PTEB Teb;
  911. BOOL AlreadyOwner;
  912. Teb = NtCurrentTeb();
  913. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  914. RtlDllShutdownInProgress() == FALSE ) {
  915. CurrentThread = Teb->ClientId.UniqueThread;
  916. //
  917. // Verify that the CS was initialized.
  918. //
  919. CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection);
  920. if (CritSectSplayNode != NULL)
  921. {
  922. InterlockedExchangePointer (&CritSectSplayNode->EnterThread,
  923. (PVOID)CurrentThread);
  924. }
  925. //
  926. // The EnterCriticalSection algorithm starts here.
  927. //
  928. Status = STATUS_SUCCESS;
  929. SpinCount = CriticalSection->SpinCount;
  930. if (SpinCount == 0) {
  931. //
  932. // Zero spincount for this CS.
  933. //
  934. EnterZeroSpinCount:
  935. LockCount = InterlockedIncrement (&CriticalSection->LockCount);
  936. if (LockCount == 0) {
  937. EnterSetOwnerAndRecursion:
  938. //
  939. // The current thread is the new owner of the CS.
  940. //
  941. //
  942. // Sanity test for the OwningThread.
  943. //
  944. if (CriticalSection->OwningThread != 0) {
  945. //
  946. // The loader lock gets handled differently, so don't assert on it.
  947. //
  948. if (CriticalSection != NtCurrentPeb()->LoaderLock ||
  949. CriticalSection->OwningThread != CurrentThread) {
  950. //
  951. // OwningThread should have been 0.
  952. //
  953. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_OWNER | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  954. "invalid critical section owner thread",
  955. CriticalSection, "Critical section address",
  956. CriticalSection->OwningThread, "Owning thread",
  957. 0, "Expected owning thread",
  958. CriticalSection->DebugInfo, "Critical section debug info address");
  959. }
  960. }
  961. //
  962. // Sanity test for the RecursionCount.
  963. //
  964. if (CriticalSection->RecursionCount != 0) {
  965. //
  966. // The loader lock gets handled differently, so don't assert on it.
  967. //
  968. if (CriticalSection != NtCurrentPeb()->LoaderLock) {
  969. //
  970. // RecursionCount should have been 0.
  971. //
  972. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_INVALID_RECURSION_COUNT | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  973. "invalid critical section recursion count",
  974. CriticalSection, "Critical section address",
  975. CriticalSection->RecursionCount, "Recursion count",
  976. 0, "Expected recursion count",
  977. CriticalSection->DebugInfo, "Critical section debug info address");
  978. }
  979. }
  980. //
  981. // Set the CS owner
  982. //
  983. CriticalSection->OwningThread = CurrentThread;
  984. //
  985. // Set the recursion count
  986. //
  987. // ntdll\ia64\critsect.s is using RecursionCount = 0 first time
  988. // the current thread is acquiring the CS.
  989. //
  990. // ntdll\i386\critsect.asm is using RecursionCount = 1 first time
  991. // the current thread is acquiring the CS.
  992. //
  993. #if defined(_IA64_)
  994. CriticalSection->RecursionCount = 0;
  995. #else //#if defined(_IA64_)
  996. CriticalSection->RecursionCount = 1;
  997. #endif
  998. AVrfpIncrementOwnedCriticalSections (1);
  999. //
  1000. // We are updating this counter on all platforms,
  1001. // unlike the ntdll code that does this only on x86 chk.
  1002. // We need the updated counter in the TEB to speed up
  1003. // ntdll!RtlCheckHeldCriticalSections.
  1004. //
  1005. Teb->CountOfOwnedCriticalSections += 1;
  1006. #if DBG && defined (_X86_)
  1007. CriticalSection->DebugInfo->EntryCount += 1;
  1008. #endif
  1009. //
  1010. // All done, CriticalSection is owned by the current thread.
  1011. //
  1012. }
  1013. else if (LockCount > 0) {
  1014. //
  1015. // The CS is currently owned by the current or another thread.
  1016. //
  1017. if (CriticalSection->OwningThread == CurrentThread) {
  1018. //
  1019. // The current thread is already the owner.
  1020. //
  1021. CriticalSection->RecursionCount += 1;
  1022. #if DBG && defined (_X86_)
  1023. //
  1024. // In a chk build we are updating this additional counter,
  1025. // just like the original function in ntdll does.
  1026. //
  1027. CriticalSection->DebugInfo->EntryCount += 1;
  1028. #endif
  1029. //
  1030. // All done, CriticalSection was already owned by
  1031. // the current thread and we have just incremented the RecursionCount.
  1032. //
  1033. }
  1034. else {
  1035. //
  1036. // The current thread is not the owner. Wait for ownership
  1037. //
  1038. if (CritSectSplayNode != NULL)
  1039. {
  1040. InterlockedExchangePointer (&CritSectSplayNode->WaitThread,
  1041. (PVOID)CurrentThread);
  1042. }
  1043. RtlpWaitForCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection);
  1044. if (CritSectSplayNode != NULL)
  1045. {
  1046. InterlockedExchangePointer (&CritSectSplayNode->WaitThread,
  1047. (PVOID)( (ULONG_PTR)CurrentThread | 0x1 ));
  1048. }
  1049. //
  1050. // We have just aquired the CS.
  1051. //
  1052. goto EnterSetOwnerAndRecursion;
  1053. }
  1054. }
  1055. else {
  1056. //
  1057. // The original LockCount was < -1 so the CS was
  1058. // over-released or corrupted.
  1059. //
  1060. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1061. "critical section over-released or corrupted",
  1062. CriticalSection, "Critical section address",
  1063. CriticalSection->LockCount, "Lock count",
  1064. 0, "Expected minimum lock count",
  1065. CriticalSection->DebugInfo, "Critical section debug info address");
  1066. }
  1067. }
  1068. else {
  1069. //
  1070. // SpinCount > 0 for this CS
  1071. //
  1072. if( CriticalSection->OwningThread == CurrentThread ) {
  1073. //
  1074. // The current thread is already the owner.
  1075. //
  1076. InterlockedIncrement( &CriticalSection->LockCount );
  1077. CriticalSection->RecursionCount += 1;
  1078. #if DBG && defined (_X86_)
  1079. //
  1080. // In a chk build we are updating this additional counter,
  1081. // just like the original function in ntdll does.
  1082. //
  1083. CriticalSection->DebugInfo->EntryCount += 1;
  1084. #endif
  1085. //
  1086. // All done, CriticalSection was already owned by the current thread
  1087. // and we have just incremented the LockCount and RecursionCount.
  1088. //
  1089. }
  1090. else {
  1091. //
  1092. // The current thread is not the owner. Attempt to acquire.
  1093. //
  1094. EnterTryAcquire:
  1095. LockCount = InterlockedCompareExchange( &CriticalSection->LockCount,
  1096. 0,
  1097. -1 );
  1098. if (LockCount == -1) {
  1099. //
  1100. // We have just aquired the CS.
  1101. //
  1102. goto EnterSetOwnerAndRecursion;
  1103. }
  1104. else {
  1105. //
  1106. // Look if there are already other threads spinning while
  1107. // waiting for this CS.
  1108. //
  1109. if (CriticalSection->LockCount >= 1) {
  1110. //
  1111. // There are other waiters for this CS.
  1112. // Do not spin, just wait for the CS to be
  1113. // released as if we had 0 spin count from the beginning.
  1114. //
  1115. goto EnterZeroSpinCount;
  1116. }
  1117. else {
  1118. //
  1119. // No other threads are waiting for this CS.
  1120. //
  1121. EnterSpinOnLockCount:
  1122. if (CriticalSection->LockCount == -1) {
  1123. //
  1124. // We have a chance for aquiring it now
  1125. //
  1126. goto EnterTryAcquire;
  1127. }
  1128. else {
  1129. //
  1130. // The CS is still owned.
  1131. // Decrement the spin count and decide if we should continue
  1132. // to spin or simply wait for the CS's event.
  1133. //
  1134. SpinCount -= 1;
  1135. if (SpinCount > 0) {
  1136. //
  1137. // Spin
  1138. //
  1139. goto EnterSpinOnLockCount;
  1140. }
  1141. else {
  1142. //
  1143. // Spun enough, just wait for the CS to be
  1144. // released as if we had 0 spin count from the beginning.
  1145. //
  1146. goto EnterZeroSpinCount;
  1147. }
  1148. }
  1149. }
  1150. }
  1151. }
  1152. }
  1153. }
  1154. else {
  1155. //
  1156. // The CS verifier is not enabled
  1157. //
  1158. Status = RtlEnterCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection);
  1159. if (NT_SUCCESS(Status)) {
  1160. #if defined(_IA64_)
  1161. AlreadyOwner = (CriticalSection->RecursionCount > 0);
  1162. #else
  1163. AlreadyOwner = (CriticalSection->RecursionCount > 1);
  1164. #endif //#if defined(_IA64_)
  1165. if (AlreadyOwner == FALSE) {
  1166. AVrfpIncrementOwnedCriticalSections (1);
  1167. #if !DBG || !defined (_X86_)
  1168. //
  1169. // We are updating this counter on all platforms,
  1170. // unlike the ntdll code that does this only on x86 chk.
  1171. // We need the updated counter in the TEB to speed up
  1172. // ntdll!RtlCheckHeldCriticalSections.
  1173. //
  1174. Teb->CountOfOwnedCriticalSections += 1;
  1175. #endif //#if !DBG || !defined (_X86_)
  1176. }
  1177. }
  1178. }
  1179. if (NT_SUCCESS (Status)) {
  1180. //
  1181. // Tell deadlock verifier that the lock has been acquired.
  1182. //
  1183. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
  1184. AVrfDeadlockResourceAcquire ((PVOID)CriticalSection,
  1185. _ReturnAddress(),
  1186. FALSE);
  1187. }
  1188. //
  1189. // We will introduce a random delay
  1190. // in order to randomize the timings in the process.
  1191. //
  1192. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_RACE_CHECKS)) {
  1193. AVrfpCreateRandomDelay ();
  1194. }
  1195. }
  1196. return Status;
  1197. }
  1198. #if defined(_X86_)
  1199. #pragma optimize("y", off) // disable FPO
  1200. #endif
  1201. //NTSYSAPI
  1202. NTSTATUS
  1203. NTAPI
  1204. AVrfpRtlLeaveCriticalSection(
  1205. volatile RTL_CRITICAL_SECTION *CriticalSection
  1206. )
  1207. {
  1208. NTSTATUS Status;
  1209. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  1210. BOOL LeavingRecursion;
  1211. //
  1212. // Tell deadlock verifier that the lock has been released.
  1213. // Note that we need to do this before the actual critical section
  1214. // gets released since otherwise we get into race issues where some other
  1215. // thread manages to enter/leave the critical section.
  1216. //
  1217. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
  1218. AVrfDeadlockResourceRelease ((PVOID)CriticalSection,
  1219. _ReturnAddress());
  1220. }
  1221. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  1222. RtlDllShutdownInProgress() == FALSE) {
  1223. //
  1224. // Verify that the CS was initialized.
  1225. //
  1226. CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection);
  1227. if (CritSectSplayNode != NULL)
  1228. {
  1229. InterlockedExchangePointer (&CritSectSplayNode->LeaveThread,
  1230. (PVOID)NtCurrentTeb()->ClientId.UniqueThread);
  1231. //
  1232. // Verify that the CS is owned by the the current thread.
  1233. //
  1234. AVrfpVerifyCriticalSectionOwner (CriticalSection,
  1235. TRUE);
  1236. }
  1237. }
  1238. //
  1239. // We need to know if we are just leaving CS ownership recursion
  1240. // because in that case we don't decrement Teb->CountOfOwnedCriticalSections.
  1241. //
  1242. // ntdll\ia64\critsect.s is using RecursionCount = 0 first time
  1243. // the current thread is acquiring the CS.
  1244. //
  1245. // ntdll\i386\critsect.asm is using RecursionCount = 1 first time
  1246. // the current thread is acquiring the CS.
  1247. //
  1248. #if defined(_IA64_)
  1249. LeavingRecursion = (CriticalSection->RecursionCount > 0);
  1250. #else
  1251. LeavingRecursion = (CriticalSection->RecursionCount > 1);
  1252. #endif //#if defined(_IA64_)
  1253. Status = RtlLeaveCriticalSection ((PRTL_CRITICAL_SECTION)CriticalSection);
  1254. if (NT_SUCCESS (Status)) {
  1255. if (LeavingRecursion == FALSE) {
  1256. AVrfpIncrementOwnedCriticalSections (-1);
  1257. #if !DBG || !defined (_X86_)
  1258. //
  1259. // We are updating this counter on all platforms,
  1260. // unlike the ntdll code that does this only on x86 chk.
  1261. // We need the updated counter in the TEB to speed up
  1262. // ntdll!RtlCheckHeldCriticalSections.
  1263. //
  1264. NtCurrentTeb()->CountOfOwnedCriticalSections -= 1;
  1265. #endif //#if !DBG || !defined (_X86_)
  1266. }
  1267. }
  1268. return Status;
  1269. }
  1270. #if defined(_X86_)
  1271. #pragma optimize("y", off) // disable FPO
  1272. #endif
  1273. //NTSYSAPI
  1274. NTSTATUS
  1275. NTAPI
  1276. AVrfpRtlInitializeCriticalSectionAndSpinCount(
  1277. PRTL_CRITICAL_SECTION CriticalSection,
  1278. ULONG SpinCount
  1279. )
  1280. {
  1281. NTSTATUS Status;
  1282. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  1283. PVOID TraceAddress;
  1284. Status = STATUS_SUCCESS;
  1285. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) {
  1286. DbgPrint ("AVrfpRtlInitializeCriticalSectionAndSpinCount (%p)\n",
  1287. CriticalSection);
  1288. }
  1289. //
  1290. // We cannot use the CriticalSectionLock after shutdown started,
  1291. // because the RTL critical sections stop working at that time.
  1292. //
  1293. if (RtlDllShutdownInProgress() == FALSE) {
  1294. //
  1295. // Grab the CS splay tree lock.
  1296. //
  1297. RtlEnterCriticalSection( &CriticalSectionLock );
  1298. try {
  1299. //
  1300. // Check if the CS is already initialized.
  1301. //
  1302. CritSectSplayNode = AVrfpFindCritSectInSplayTree (CriticalSection);
  1303. if (CritSectSplayNode != NULL &&
  1304. (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0) {
  1305. //
  1306. // The caller is trying to reinitialize this CS.
  1307. //
  1308. if (AVrfpGetStackTraceAddress != NULL) {
  1309. TraceAddress = AVrfpGetStackTraceAddress (CritSectSplayNode->DebugInfo->CreatorBackTraceIndex);
  1310. }
  1311. else {
  1312. TraceAddress = NULL;
  1313. }
  1314. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1315. "reinitializing critical section",
  1316. CritSectSplayNode->CriticalSection, "Critical section address",
  1317. CritSectSplayNode->DebugInfo, "Critical section debug info address",
  1318. TraceAddress, "First initialization stack trace. Use dds to dump it if non-NULL.",
  1319. NULL, "" );
  1320. }
  1321. //
  1322. // Call the regular CS initialization routine in ntdll.
  1323. // This will allocate heap for the DebugInfo so we need to temporarily
  1324. // drop CriticalSectionLock, otherwise we can deadlock with the heap lock.
  1325. //
  1326. RtlLeaveCriticalSection (&CriticalSectionLock);
  1327. try {
  1328. Status = RtlInitializeCriticalSectionAndSpinCount (CriticalSection,
  1329. SpinCount);
  1330. }
  1331. finally {
  1332. RtlEnterCriticalSection (&CriticalSectionLock);
  1333. }
  1334. if (NT_SUCCESS (Status)) {
  1335. //
  1336. // Insert the CS in our splay tree.
  1337. //
  1338. Status = AVrfpInsertCritSectInSplayTree (CriticalSection);
  1339. if (!NT_SUCCESS( Status )) {
  1340. //
  1341. // Undo the ntdll initialization. This will use the heap to free up
  1342. // the debug info so we need to temporarily drop CriticalSectionLock,
  1343. // otherwise we can deadlock with the heap lock.
  1344. //
  1345. RtlLeaveCriticalSection (&CriticalSectionLock);
  1346. try {
  1347. RtlDeleteCriticalSection (CriticalSection);
  1348. }
  1349. finally {
  1350. RtlEnterCriticalSection (&CriticalSectionLock);
  1351. }
  1352. }
  1353. }
  1354. }
  1355. finally {
  1356. //
  1357. // Release the CS splay tree lock.
  1358. //
  1359. RtlLeaveCriticalSection( &CriticalSectionLock );
  1360. }
  1361. }
  1362. else {
  1363. Status = RtlInitializeCriticalSectionAndSpinCount (CriticalSection,
  1364. SpinCount);
  1365. }
  1366. //
  1367. // Register the lock with deadlock verifier.
  1368. //
  1369. if (NT_SUCCESS(Status)) {
  1370. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
  1371. AVrfDeadlockResourceInitialize (CriticalSection,
  1372. _ReturnAddress());
  1373. }
  1374. }
  1375. return Status;
  1376. }
  1377. #if defined(_X86_)
  1378. #pragma optimize("y", off) // disable FPO
  1379. #endif
  1380. //NTSYSAPI
  1381. NTSTATUS
  1382. NTAPI
  1383. AVrfpRtlInitializeCriticalSection(
  1384. PRTL_CRITICAL_SECTION CriticalSection
  1385. )
  1386. {
  1387. return AVrfpRtlInitializeCriticalSectionAndSpinCount (CriticalSection,
  1388. 0);
  1389. }
  1390. #if defined(_X86_)
  1391. #pragma optimize("y", off) // disable FPO
  1392. #endif
  1393. //NTSYSAPI
  1394. NTSTATUS
  1395. NTAPI
  1396. AVrfpRtlDeleteCriticalSection(
  1397. PRTL_CRITICAL_SECTION CriticalSection
  1398. )
  1399. {
  1400. NTSTATUS Status;
  1401. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  1402. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) {
  1403. DbgPrint ("AVrfpRtlDeleteCriticalSection (%p)\n",
  1404. CriticalSection);
  1405. }
  1406. //
  1407. // We cannot use the CriticalSectionLock after shutdown started,
  1408. // because the RTL critical sections stop working at that time.
  1409. //
  1410. if (RtlDllShutdownInProgress() == FALSE) {
  1411. //
  1412. // Grab the CS splay tree lock.
  1413. //
  1414. RtlEnterCriticalSection( &CriticalSectionLock );
  1415. try {
  1416. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  1417. RtlDllShutdownInProgress() == FALSE ) {
  1418. //
  1419. // Verify that the CS was initialized.
  1420. //
  1421. CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection);
  1422. if (CritSectSplayNode != NULL) {
  1423. //
  1424. // Verify that no thread owns or waits for this CS or
  1425. // the owner is the current thread.
  1426. //
  1427. AVrfpVerifyNoWaitersCriticalSection (CriticalSection);
  1428. }
  1429. }
  1430. //
  1431. // Remove the critical section from our splay tree.
  1432. //
  1433. AVrfpDeleteCritSectFromSplayTree (CriticalSection);
  1434. }
  1435. finally {
  1436. //
  1437. // Release the CS splay tree lock.
  1438. //
  1439. RtlLeaveCriticalSection( &CriticalSectionLock );
  1440. }
  1441. }
  1442. //
  1443. // Regular ntdll CS deletion.
  1444. //
  1445. Status = RtlDeleteCriticalSection (CriticalSection);
  1446. //
  1447. // Deregister the lock from deadlock verifier structures.
  1448. //
  1449. if (NT_SUCCESS(Status)) {
  1450. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_DEADLOCK_CHECKS) != 0) {
  1451. AVrfDeadlockResourceDelete (CriticalSection,
  1452. _ReturnAddress());
  1453. }
  1454. }
  1455. return Status;
  1456. }
  1457. #if defined(_X86_)
  1458. #pragma optimize("y", off) // disable FPO
  1459. #endif
  1460. VOID
  1461. AVrfpRtlInitializeResource(
  1462. IN PRTL_RESOURCE Resource
  1463. )
  1464. {
  1465. NTSTATUS Status;
  1466. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  1467. PVOID TraceAddress;
  1468. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) {
  1469. DbgPrint ("AVrfpRtlInitializeResource (%p), CS = %p\n",
  1470. Resource,
  1471. &Resource->CriticalSection);
  1472. }
  1473. //
  1474. // We cannot use the CriticalSectionLock after shutdown started,
  1475. // because the RTL critical sections stop working at that time.
  1476. //
  1477. if (RtlDllShutdownInProgress() == FALSE) {
  1478. //
  1479. // Grab the CS splay tree lock.
  1480. //
  1481. RtlEnterCriticalSection( &CriticalSectionLock );
  1482. try {
  1483. //
  1484. // Check if the CS is already initialized.
  1485. //
  1486. CritSectSplayNode = AVrfpFindCritSectInSplayTree (&Resource->CriticalSection);
  1487. if (CritSectSplayNode != NULL &&
  1488. (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0) {
  1489. //
  1490. // The caller is trying to reinitialize this CS.
  1491. //
  1492. if (AVrfpGetStackTraceAddress != NULL) {
  1493. TraceAddress = AVrfpGetStackTraceAddress (CritSectSplayNode->DebugInfo->CreatorBackTraceIndex);
  1494. }
  1495. else {
  1496. TraceAddress = NULL;
  1497. }
  1498. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_ALREADY_INITIALIZED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1499. "reinitializing critical section",
  1500. CritSectSplayNode->CriticalSection, "Critical section address",
  1501. CritSectSplayNode->DebugInfo, "Critical section debug info address",
  1502. TraceAddress, "First initialization stack trace. Use dds to dump it if non-NULL.",
  1503. NULL, "" );
  1504. }
  1505. //
  1506. // Call the regular CS initialization routine in ntdll.
  1507. // This will allocate heap for the DebugInfo so we need to temporarily
  1508. // drop CriticalSectionLock, otherwise we can deadlock with the heap lock.
  1509. //
  1510. RtlLeaveCriticalSection (&CriticalSectionLock);
  1511. try {
  1512. RtlInitializeResource (Resource);
  1513. }
  1514. finally {
  1515. RtlEnterCriticalSection (&CriticalSectionLock);
  1516. }
  1517. //
  1518. // Insert the CS in our splay tree.
  1519. //
  1520. Status = AVrfpInsertCritSectInSplayTree (&Resource->CriticalSection);
  1521. if (!NT_SUCCESS( Status )) {
  1522. //
  1523. // Undo the ntdll initialization. This will use the heap to free up
  1524. // the debug info so we need to temporarily drop CriticalSectionLock,
  1525. // otherwise we can deadlock with the heap lock.
  1526. //
  1527. RtlLeaveCriticalSection (&CriticalSectionLock);
  1528. try {
  1529. RtlDeleteResource (Resource);
  1530. }
  1531. finally {
  1532. RtlEnterCriticalSection (&CriticalSectionLock);
  1533. }
  1534. //
  1535. // Raise an exception for failure case, just like ntdll does for resources.
  1536. //
  1537. RtlRaiseStatus(Status);
  1538. }
  1539. }
  1540. finally {
  1541. //
  1542. // Release the CS splay tree lock.
  1543. //
  1544. RtlLeaveCriticalSection( &CriticalSectionLock );
  1545. }
  1546. }
  1547. else {
  1548. RtlInitializeResource (Resource);
  1549. }
  1550. }
  1551. #if defined(_X86_)
  1552. #pragma optimize("y", off) // disable FPO
  1553. #endif
  1554. VOID
  1555. AVrfpRtlDeleteResource (
  1556. IN PRTL_RESOURCE Resource
  1557. )
  1558. {
  1559. PRTL_CRITICAL_SECTION CriticalSection;
  1560. PCRITICAL_SECTION_SPLAY_NODE CritSectSplayNode;
  1561. CriticalSection = &Resource->CriticalSection;
  1562. if ((AVrfpProvider.VerifierDebug & VRFP_DEBUG_LOCKS_INITIALIZE_DELETE) != 0) {
  1563. DbgPrint ("AVrfpRtlDeleteResource (%p), CS = %p\n",
  1564. Resource,
  1565. CriticalSection);
  1566. }
  1567. //
  1568. // We cannot use the CriticalSectionLock after shutdown started,
  1569. // because the RTL critical sections stop working at that time.
  1570. //
  1571. if (RtlDllShutdownInProgress() == FALSE) {
  1572. //
  1573. // Grab the CS splay tree lock.
  1574. //
  1575. RtlEnterCriticalSection( &CriticalSectionLock );
  1576. try {
  1577. if ((AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  1578. RtlDllShutdownInProgress() == FALSE ) {
  1579. //
  1580. // Verify that the CS was initialized.
  1581. //
  1582. CritSectSplayNode = AVrfpVerifyInitializedCriticalSection (CriticalSection);
  1583. if (CritSectSplayNode != NULL) {
  1584. //
  1585. // Verify that no thread owns or waits for this CS or
  1586. // the owner is the current thread.
  1587. //
  1588. AVrfpVerifyNoWaitersCriticalSection (CriticalSection);
  1589. }
  1590. }
  1591. //
  1592. // Remove the critical section from our splay tree.
  1593. //
  1594. AVrfpDeleteCritSectFromSplayTree (CriticalSection);
  1595. }
  1596. finally {
  1597. //
  1598. // Release the CS splay tree lock.
  1599. //
  1600. RtlLeaveCriticalSection( &CriticalSectionLock );
  1601. }
  1602. }
  1603. //
  1604. // Regular ntdll resource deletion.
  1605. //
  1606. RtlDeleteResource (Resource);
  1607. }
  1608. #if defined(_X86_)
  1609. #pragma optimize("y", off) // disable FPO
  1610. #endif
  1611. BOOLEAN
  1612. AVrfpRtlAcquireResourceShared (
  1613. IN PRTL_RESOURCE Resource,
  1614. IN BOOLEAN Wait
  1615. )
  1616. {
  1617. //
  1618. // Verify that the CS was initialized.
  1619. //
  1620. AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection);
  1621. //
  1622. // Call the regular ntdll function.
  1623. //
  1624. return RtlAcquireResourceShared (Resource,
  1625. Wait);
  1626. }
  1627. BOOLEAN
  1628. AVrfpRtlAcquireResourceExclusive (
  1629. IN PRTL_RESOURCE Resource,
  1630. IN BOOLEAN Wait
  1631. )
  1632. {
  1633. //
  1634. // Verify that the CS was initialized.
  1635. //
  1636. AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection);
  1637. //
  1638. // Call the regular ntdll function.
  1639. //
  1640. return RtlAcquireResourceExclusive (Resource,
  1641. Wait);
  1642. }
  1643. #if defined(_X86_)
  1644. #pragma optimize("y", off) // disable FPO
  1645. #endif
  1646. VOID
  1647. AVrfpRtlReleaseResource (
  1648. IN PRTL_RESOURCE Resource
  1649. )
  1650. {
  1651. //
  1652. // Verify that the CS was initialized.
  1653. //
  1654. AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection);
  1655. //
  1656. // Call the regular ntdll function.
  1657. //
  1658. RtlReleaseResource (Resource);
  1659. }
  1660. #if defined(_X86_)
  1661. #pragma optimize("y", off) // disable FPO
  1662. #endif
  1663. VOID
  1664. AVrfpRtlConvertSharedToExclusive(
  1665. IN PRTL_RESOURCE Resource
  1666. )
  1667. {
  1668. //
  1669. // Verify that the CS was initialized.
  1670. //
  1671. AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection);
  1672. //
  1673. // Call the regular ntdll function.
  1674. //
  1675. RtlConvertSharedToExclusive (Resource);
  1676. }
  1677. #if defined(_X86_)
  1678. #pragma optimize("y", off) // disable FPO
  1679. #endif
  1680. VOID
  1681. AVrfpRtlConvertExclusiveToShared (
  1682. IN PRTL_RESOURCE Resource
  1683. )
  1684. {
  1685. //
  1686. // Verify that the CS was initialized.
  1687. //
  1688. AVrfpVerifyInitializedCriticalSection2 (&Resource->CriticalSection);
  1689. //
  1690. // Call the regular ntdll function.
  1691. //
  1692. RtlConvertExclusiveToShared (Resource);
  1693. }
  1694. LONG AVrfpCSCountHacks = 0;
  1695. VOID
  1696. AVrfpIncrementOwnedCriticalSections (
  1697. LONG Increment
  1698. )
  1699. {
  1700. PAVRF_TLS_STRUCT TlsStruct;
  1701. TlsStruct = AVrfpGetVerifierTlsValue();
  1702. if (TlsStruct != NULL) {
  1703. TlsStruct->CountOfOwnedCriticalSections += Increment;
  1704. if (TlsStruct->CountOfOwnedCriticalSections < 0 &&
  1705. (AVrfpProvider.VerifierFlags & RTL_VRF_FLG_LOCK_CHECKS) != 0 &&
  1706. RtlDllShutdownInProgress() == FALSE ) {
  1707. VERIFIER_STOP (APPLICATION_VERIFIER_LOCK_OVER_RELEASED | APPLICATION_VERIFIER_CONTINUABLE_BREAK,
  1708. "critical section over-released or corrupted",
  1709. TlsStruct->CountOfOwnedCriticalSections, "Number of critical sections owned by curent thread.",
  1710. NULL, "",
  1711. NULL, "",
  1712. NULL, "");
  1713. //
  1714. // Hack:
  1715. //
  1716. // If the number of owned critical sections became -1 (over-release) we are
  1717. // resetting it to 0 because otherwise we will keep breaking for
  1718. // every future legitimate critical section usage by this thread.
  1719. //
  1720. if (TlsStruct->CountOfOwnedCriticalSections == -1) {
  1721. InterlockedIncrement (&AVrfpCSCountHacks);
  1722. TlsStruct->CountOfOwnedCriticalSections = 0;
  1723. }
  1724. }
  1725. }
  1726. }