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.

1302 lines
32 KiB

  1. //
  2. // Page heap command line manipulator
  3. // Copyright (c) Microsoft Corporation, 1999
  4. //
  5. // -- History --
  6. //
  7. // 3.04 Whistler: protect page heap meta data option
  8. // 3.03 Whistler: more granular fault injection option
  9. // 3.02 Whistler: leaks detection
  10. // 3.01 Whistler: fault injection
  11. // 3.00 Whistler/W2000 SP1
  12. //
  13. //
  14. // module: pageheap.cxx
  15. // author: silviuc
  16. // created: Tue Feb 02 10:43:04 1999
  17. //
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <stdarg.h>
  21. #include <malloc.h>
  22. #include <tchar.h>
  23. #include <nt.h>
  24. #include <ntrtl.h>
  25. #include <nturtl.h>
  26. #include <windows.h>
  27. #include <common.ver>
  28. //
  29. // Definitions copied from \nt\base\ntos\inc\heappage.h
  30. //
  31. #define PAGE_HEAP_ENABLE_PAGE_HEAP 0x0001
  32. #define PAGE_HEAP_COLLECT_STACK_TRACES 0x0002
  33. #define PAGE_HEAP_RESERVED_04 0x0004
  34. #define PAGE_HEAP_RESERVED_08 0x0008
  35. #define PAGE_HEAP_CATCH_BACKWARD_OVERRUNS 0x0010
  36. #define PAGE_HEAP_UNALIGNED_ALLOCATIONS 0x0020
  37. #define PAGE_HEAP_SMART_MEMORY_USAGE 0x0040
  38. #define PAGE_HEAP_USE_SIZE_RANGE 0x0080
  39. #define PAGE_HEAP_USE_DLL_RANGE 0x0100
  40. #define PAGE_HEAP_USE_RANDOM_DECISION 0x0200
  41. #define PAGE_HEAP_USE_DLL_NAMES 0x0400
  42. #define PAGE_HEAP_USE_FAULT_INJECTION 0x0800
  43. #define PAGE_HEAP_PROTECT_META_DATA 0x1000
  44. #define PAGE_HEAP_CHECK_NO_SERIALIZE_ACCESS 0x2000
  45. #define PAGE_HEAP_NO_LOCK_CHECKS 0x4000
  46. VOID
  47. PrintFlags (
  48. DWORD Flags,
  49. BOOL ShutdownFlagsDefined = FALSE
  50. )
  51. {
  52. if ((Flags & PAGE_HEAP_ENABLE_PAGE_HEAP)) {
  53. printf("full ");
  54. }
  55. if ((Flags & PAGE_HEAP_CATCH_BACKWARD_OVERRUNS)) {
  56. printf("backwards ");
  57. }
  58. if ((Flags & PAGE_HEAP_UNALIGNED_ALLOCATIONS)) {
  59. printf("unaligned ");
  60. }
  61. if ((Flags & PAGE_HEAP_SMART_MEMORY_USAGE)) {
  62. printf("decommit ");
  63. }
  64. if ((Flags & PAGE_HEAP_USE_SIZE_RANGE)) {
  65. printf("size ");
  66. }
  67. if ((Flags & PAGE_HEAP_USE_DLL_RANGE)) {
  68. printf("address ");
  69. }
  70. if ((Flags & PAGE_HEAP_USE_RANDOM_DECISION)) {
  71. printf("random ");
  72. }
  73. if ((Flags & PAGE_HEAP_USE_DLL_NAMES)) {
  74. printf("dlls ");
  75. }
  76. if ((Flags & PAGE_HEAP_USE_FAULT_INJECTION)) {
  77. printf("fault ");
  78. }
  79. if ((Flags & PAGE_HEAP_COLLECT_STACK_TRACES)) {
  80. printf("traces ");
  81. }
  82. if ((Flags & PAGE_HEAP_PROTECT_META_DATA)) {
  83. printf("protect ");
  84. }
  85. if ((Flags & PAGE_HEAP_CHECK_NO_SERIALIZE_ACCESS)) {
  86. printf("no_sync ");
  87. }
  88. if ((Flags & PAGE_HEAP_NO_LOCK_CHECKS)) {
  89. printf("no_lock_checks ");
  90. }
  91. if (ShutdownFlagsDefined) {
  92. printf("leaks ");
  93. }
  94. }
  95. BOOL
  96. EnablePageHeap (
  97. LPCTSTR Name,
  98. LPTSTR HeapFlags,
  99. LPTSTR DebugString,
  100. char * * Args);
  101. BOOL
  102. DisablePageHeap (
  103. LPCTSTR Name);
  104. BOOL
  105. IsPageHeapEnabled (
  106. LPCTSTR Name);
  107. BOOL
  108. IsPageHeapFlagsValueDefined (
  109. LPCTSTR Name,
  110. PDWORD Value);
  111. BOOL
  112. ReadGlobalFlagValue (
  113. HKEY Key,
  114. LPTSTR Buffer,
  115. ULONG Length);
  116. BOOL
  117. WriteGlobalFlagValue (
  118. HKEY Key,
  119. LPTSTR Buffer,
  120. ULONG Length);
  121. BOOL
  122. ReadHeapFlagValue (
  123. HKEY Key,
  124. LPTSTR Buffer,
  125. ULONG Length);
  126. BOOL
  127. WriteHeapFlagValue (
  128. HKEY Key,
  129. LPTSTR Buffer,
  130. ULONG Length);
  131. BOOL
  132. DeleteHeapFlagValue (
  133. HKEY Key);
  134. BOOL
  135. WriteDebuggerValue (
  136. HKEY Key,
  137. LPTSTR Buffer,
  138. ULONG Length);
  139. BOOL
  140. DeleteDebuggerValue (
  141. HKEY Key);
  142. HKEY
  143. OpenImageKey (
  144. LPCTSTR Name,
  145. BOOL ShouldExist);
  146. VOID
  147. CloseImageKey (
  148. HKEY Key);
  149. VOID
  150. CreateImageName (
  151. LPCTSTR Source,
  152. LPTSTR Name,
  153. ULONG Length);
  154. VOID
  155. PrintPageheapEnabledApplications (
  156. );
  157. VOID
  158. Help (
  159. );
  160. __declspec(noreturn)
  161. VOID
  162. __cdecl
  163. Error (
  164. LPCTSTR Format,
  165. ...);
  166. BOOL
  167. IsWow64Active (
  168. );
  169. //////////////////////////////////////////////////////////////////////
  170. //////////////////////////////////////////////////////////////////////
  171. //////////////////////////////////////////////////////////////////////
  172. char * *
  173. SearchOption (
  174. char * Args[],
  175. char * Option
  176. )
  177. {
  178. while (*Args) {
  179. if (_stricmp(*Args, Option) == 0) {
  180. return Args;
  181. }
  182. Args++;
  183. }
  184. return NULL;
  185. }
  186. #pragma warning(disable:4706)
  187. void _cdecl
  188. #if defined (_PART_OF_GFLAGS_)
  189. PageHeapMain (int argc, char *argv[])
  190. #else
  191. main (int argc, char *argv[])
  192. #endif
  193. {
  194. TCHAR ImageName [MAX_PATH + 1];
  195. char * * Option;
  196. if (IsWow64Active()) {
  197. _tprintf (TEXT ("Warning: pageheap.exe is running inside WOW64. \n"
  198. "This scenario can be used to test x86 binaries (running inside WOW64) \n"
  199. "but not native (IA64) binaries. \n\n"));
  200. }
  201. if (argc == 2 && strstr (argv[1], TEXT("?")) != NULL) {
  202. Help ();
  203. }
  204. else if ((Option = SearchOption(argv + 1, "/enable"))) {
  205. PCHAR DebugString = NULL;
  206. if (SearchOption (argv + 1, "/debug") != NULL) {
  207. DebugString = "ntsd -g -G -x";
  208. }
  209. if (SearchOption (argv + 1, "/kdebug") != NULL) {
  210. DebugString = "ntsd -g -G -d -x";
  211. }
  212. if (Option[1] && Option[1][0] != '/') {
  213. CreateImageName (Option[1], ImageName, MAX_PATH + 1);
  214. EnablePageHeap (ImageName, NULL, DebugString, argv);
  215. }
  216. else {
  217. Help();
  218. }
  219. }
  220. else if ((Option = SearchOption(argv + 1, "/disable"))) {
  221. if (Option[1]) {
  222. CreateImageName (Option[1], ImageName, MAX_PATH + 1);
  223. DisablePageHeap (ImageName);
  224. }
  225. else {
  226. Help();
  227. }
  228. }
  229. else if (argc == 2) {
  230. CreateImageName (argv[1], ImageName, MAX_PATH + 1);
  231. if (IsPageHeapEnabled (ImageName) == FALSE) {
  232. _tprintf (TEXT("Page heap is not enabled for %s\n"), argv[1]);
  233. }
  234. else {
  235. DWORD Value;
  236. if (IsPageHeapFlagsValueDefined (ImageName, &Value)) {
  237. _tprintf (TEXT("Page heap is enabled for %s with flags ("), argv[1]);
  238. PrintFlags (Value);
  239. _tprintf (TEXT(")\n"));
  240. }
  241. else {
  242. _tprintf (TEXT("Page heap is enabled for %s with flags ("), argv[1]);
  243. PrintFlags (0);
  244. _tprintf (TEXT(")\n"));
  245. }
  246. }
  247. }
  248. else {
  249. PrintPageheapEnabledApplications ();
  250. }
  251. }
  252. VOID
  253. Help (
  254. )
  255. {
  256. _tprintf (
  257. TEXT("pageheap - Page heap utility, v 3.04 \n")
  258. VER_LEGALCOPYRIGHT_STR TEXT("\n")
  259. TEXT(" \n")
  260. TEXT("pageheap [OPTION [OPTION ...]] \n")
  261. TEXT(" \n")
  262. TEXT(" /enable PROGRAM Enable page heap with default settings. \n")
  263. TEXT(" /disable PROGRAM Disable page heap. \n")
  264. TEXT(" /full Page heap for all allocations. \n")
  265. TEXT(" /size START END Page heap allocations for size range. \n")
  266. TEXT(" /address START END Page heap allocations for address range. \n")
  267. TEXT(" /dlls DLL ... Page heap allocations for target dlls. \n")
  268. TEXT(" /random PROBABILITY Page heap allocations with PROBABILITY. \n")
  269. TEXT(" /debug Launch under debugger `ntsd -g -G -x'. \n")
  270. TEXT(" /kdebug Launch under debugger `ntsd -g -G -d -x'.\n")
  271. TEXT(" /backwards Catch backwards overruns. \n")
  272. TEXT(" /unaligned No alignment for allocations. \n")
  273. TEXT(" /decommit Decommit guard pages (lower memory use). \n")
  274. TEXT(" /notraces Do not collect stack traces. \n")
  275. TEXT(" /fault RATE TIMEOUT Probability (1..10000) for heap calls failures \n")
  276. TEXT(" and time during process initialization (in seconds)\n")
  277. TEXT(" when faults are not allowed. \n")
  278. TEXT(" /leaks Check for heap leaks when process shuts down. \n")
  279. TEXT(" /protect Protect heap internal structures. Can be \n")
  280. TEXT(" used to detect random corruptions but \n")
  281. TEXT(" execution is slower. \n")
  282. TEXT(" /no_sync Check for unsynchronized access. Do not \n")
  283. TEXT(" use this flag for an MPheap process. \n")
  284. TEXT(" /no_lock_checks Disable critical section verifier. \n")
  285. TEXT(" \n")
  286. TEXT(" \n")
  287. TEXT("PROGRAM Name of the binary with extension (.exe or something else).\n")
  288. TEXT("DLL Name of the binary with extension (.dll or something else).\n")
  289. TEXT("PROBABILITY Decimal integer in range [0..100] representing probability.\n")
  290. TEXT(" to make page heap allocation vs. a normal heap allocation. \n")
  291. TEXT("START..END For /size option these are decimal integers. \n")
  292. TEXT(" For /address option these are hexadecimal integers. \n")
  293. TEXT(" \n")
  294. TEXT("If no option specified the program will print all page heap enabled \n")
  295. TEXT("applications and their specific options. \n")
  296. TEXT(" \n")
  297. TEXT("The `/leaks' option is effective only when normal page heap is enabled \n")
  298. TEXT("(i.e. not full page heap) therefore all flags that will force full \n")
  299. TEXT("page heap will be disabled if /leaks is specified. \n")
  300. TEXT(" \n")
  301. TEXT("Note. Enabling page heap does not affect currently running \n")
  302. TEXT("processes. If you need to use page heap for processes that are \n")
  303. TEXT("already running and cannot be restarted (csrss.exe, winlogon.exe), \n")
  304. TEXT("a reboot is needed after the page heap has been enabled for \n")
  305. TEXT("that process. \n")
  306. TEXT(" \n")
  307. TEXT(" \n"));
  308. exit(1);
  309. }
  310. __declspec(noreturn)
  311. VOID
  312. __cdecl
  313. Error (
  314. LPCTSTR Format,
  315. ...)
  316. {
  317. va_list Params;
  318. va_start (Params, Format);
  319. _tprintf (TEXT("Error: "));
  320. _vtprintf (Format, Params);
  321. _tprintf ( TEXT("\n "));
  322. exit (1);
  323. }
  324. //////////////////////////////////////////////////////////////////////
  325. //////////////////////////////////////////////////////////////////////
  326. //////////////////////////////////////////////////////////////////////
  327. #define PAGE_HEAP_BIT 0x02000000
  328. BOOL
  329. IsPageHeapEnabled (
  330. LPCTSTR Name)
  331. {
  332. HKEY Key;
  333. TCHAR Buffer [128];
  334. DWORD Flags;
  335. BOOL Success;
  336. if ((Key = OpenImageKey (Name, TRUE)) == NULL) {
  337. return FALSE;
  338. }
  339. Success = ReadGlobalFlagValue (Key, Buffer, sizeof Buffer);
  340. CloseImageKey (Key);
  341. if (Success == FALSE) {
  342. return FALSE;
  343. }
  344. if (_stscanf (Buffer, TEXT("%x"), &Flags) != 1) {
  345. return FALSE;
  346. }
  347. return (Flags & PAGE_HEAP_BIT) ? TRUE : FALSE;
  348. }
  349. BOOL
  350. IsPageHeapFlagsValueDefined (
  351. LPCTSTR Name,
  352. PDWORD Value)
  353. {
  354. HKEY Key;
  355. TCHAR Buffer [128];
  356. BOOL Success;
  357. if ((Key = OpenImageKey (Name, TRUE)) == NULL) {
  358. return FALSE;
  359. }
  360. Success = ReadHeapFlagValue (Key, Buffer, sizeof Buffer);
  361. CloseImageKey (Key);
  362. if (Success == FALSE) {
  363. return FALSE;
  364. }
  365. if (_stscanf (Buffer, TEXT("%x"), Value) != 1) {
  366. return FALSE;
  367. }
  368. return TRUE;
  369. }
  370. BOOL
  371. EnablePageHeap (
  372. LPCTSTR Name,
  373. LPTSTR HeapFlagsString,
  374. LPTSTR DebugString,
  375. char * * Args
  376. )
  377. {
  378. HKEY Key;
  379. TCHAR Buffer [128];
  380. DWORD Flags;
  381. DWORD HeapFlags;
  382. char * * Option;
  383. LONG Result;
  384. BOOL LeakDetectionEnabled = FALSE;
  385. DWORD Scanned;
  386. if ((Key = OpenImageKey (Name, FALSE)) == NULL) {
  387. Error (TEXT("Cannot open image registry key for %s"), Name);
  388. }
  389. if (ReadGlobalFlagValue (Key, Buffer, sizeof Buffer) == FALSE) {
  390. Flags = 0;
  391. }
  392. else {
  393. Scanned = _stscanf (Buffer, TEXT("%x"), &Flags);
  394. if (Scanned != 1) {
  395. Error (TEXT("Failed to read global flags"));
  396. }
  397. }
  398. Flags |= PAGE_HEAP_BIT;
  399. _stprintf (Buffer, TEXT("0x%08X"), Flags);
  400. if (WriteGlobalFlagValue (Key, Buffer, (ULONG)_tcslen(Buffer)) == FALSE) {
  401. return FALSE;
  402. }
  403. //
  404. // Figure out if we have some page heap flags specified.
  405. //
  406. HeapFlags = 0;
  407. if (HeapFlagsString != NULL) {
  408. Scanned = _stscanf (HeapFlagsString, "%x", &HeapFlags);
  409. if (Scanned != 1) {
  410. Error (TEXT("Failed to read heap flags"));
  411. }
  412. }
  413. //
  414. // Write `Debugger' value if needed.
  415. //
  416. if (DebugString != NULL) {
  417. if (WriteDebuggerValue (Key, DebugString, (ULONG)_tcslen(DebugString)) == FALSE) {
  418. return FALSE;
  419. }
  420. }
  421. //
  422. // Check for /leaks option. This requires a normal page heap to be
  423. // fully effective. Therefore any flag that will enable full page
  424. // heap will be disabled.
  425. //
  426. if ((Option = SearchOption (Args, "/leaks")) != NULL) {
  427. DWORD ShutdownFlags = 0x03;
  428. Result = RegSetValueEx (
  429. Key, TEXT ("ShutdownFlags"), 0, REG_DWORD,
  430. (LPBYTE)(&ShutdownFlags), sizeof ShutdownFlags);
  431. if (Result) {
  432. Error (TEXT("Failed to write ShutdownFlags value: error %u"), Result);
  433. }
  434. LeakDetectionEnabled = TRUE;
  435. }
  436. //
  437. // Check for full, backward, decommit, unaligned, protect options.
  438. //
  439. HeapFlags |= PAGE_HEAP_COLLECT_STACK_TRACES;
  440. if ((Option = SearchOption (Args, "/notraces")) != NULL) {
  441. HeapFlags &= ~PAGE_HEAP_COLLECT_STACK_TRACES;
  442. }
  443. if ((Option = SearchOption (Args, "/full")) != NULL) {
  444. if (! LeakDetectionEnabled) {
  445. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  446. }
  447. else {
  448. printf("/full option disabled because /leaks is present. \n");
  449. }
  450. }
  451. if ((Option = SearchOption (Args, "/backwards")) != NULL) {
  452. if (! LeakDetectionEnabled) {
  453. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  454. HeapFlags |= PAGE_HEAP_CATCH_BACKWARD_OVERRUNS;
  455. }
  456. else {
  457. printf("/backwards option disabled because /leaks is present. \n");
  458. }
  459. }
  460. if ((Option = SearchOption (Args, "/decommit")) != NULL) {
  461. if (! LeakDetectionEnabled) {
  462. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  463. HeapFlags |= PAGE_HEAP_SMART_MEMORY_USAGE;
  464. }
  465. else {
  466. printf("/decommit option disabled because /leaks is present. \n");
  467. }
  468. }
  469. if ((Option = SearchOption (Args, "/unaligned")) != NULL) {
  470. if (! LeakDetectionEnabled) {
  471. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  472. HeapFlags |= PAGE_HEAP_UNALIGNED_ALLOCATIONS;
  473. }
  474. else {
  475. printf("/unaligned option disabled because /leaks is present. \n");
  476. }
  477. }
  478. if ((Option = SearchOption (Args, "/protect")) != NULL) {
  479. if (! LeakDetectionEnabled) {
  480. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  481. HeapFlags |= PAGE_HEAP_PROTECT_META_DATA;
  482. }
  483. else {
  484. printf("/protect option disabled because /leaks is present. \n");
  485. }
  486. }
  487. if ((Option = SearchOption (Args, "/no_sync")) != NULL) {
  488. HeapFlags |= PAGE_HEAP_CHECK_NO_SERIALIZE_ACCESS;
  489. }
  490. if ((Option = SearchOption (Args, "/no_lock_checks")) != NULL) {
  491. HeapFlags |= PAGE_HEAP_NO_LOCK_CHECKS;
  492. }
  493. //
  494. // Check /size option
  495. //
  496. Option = SearchOption (Args, "/size");
  497. if (Option != NULL) {
  498. if (!LeakDetectionEnabled && Option[1] && Option[2]) {
  499. DWORD RangeStart;
  500. DWORD RangeEnd;
  501. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  502. HeapFlags |= PAGE_HEAP_USE_SIZE_RANGE;
  503. Scanned = sscanf (Option[1], "%u", &RangeStart);
  504. if (Scanned != 1) {
  505. Error (TEXT("Failed to read start range value."));
  506. }
  507. Scanned = sscanf (Option[2], "%u", &RangeEnd);
  508. if (Scanned != 1) {
  509. Error (TEXT("Failed to read end range value."));
  510. }
  511. Result = RegSetValueEx (
  512. Key, TEXT ("PageHeapSizeRangeStart"), 0, REG_DWORD,
  513. (LPBYTE)(&RangeStart), sizeof RangeStart);
  514. if (Result) {
  515. Error (TEXT("Failed to write SizeRangeStart value: error %u"), Result);
  516. }
  517. Result = RegSetValueEx (
  518. Key, TEXT ("PageHeapSizeRangeEnd"), 0, REG_DWORD,
  519. (LPBYTE)(&RangeEnd), sizeof RangeEnd);
  520. if (Result) {
  521. Error (TEXT("Failed to write SizeRangeEnd value: error %u"), Result);
  522. }
  523. }
  524. if (LeakDetectionEnabled) {
  525. printf("/size option disabled because /leaks is present. \n");
  526. }
  527. }
  528. //
  529. // Check /address option
  530. //
  531. Option = SearchOption (Args, "/address");
  532. if (Option != NULL) {
  533. if (!LeakDetectionEnabled && Option[1] && Option[2]) {
  534. DWORD RangeStart;
  535. DWORD RangeEnd;
  536. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  537. HeapFlags |= PAGE_HEAP_USE_DLL_RANGE;
  538. Scanned = sscanf (Option[1], "%x", &RangeStart);
  539. if (Scanned != 1) {
  540. Error (TEXT("Failed to read start range value."));
  541. }
  542. Scanned = sscanf (Option[2], "%x", &RangeEnd);
  543. if (Scanned != 1) {
  544. Error (TEXT("Failed to read end range value."));
  545. }
  546. Result = RegSetValueEx (
  547. Key, TEXT ("PageHeapDllRangeStart"), 0, REG_DWORD,
  548. (LPBYTE)(&RangeStart), sizeof RangeStart);
  549. if (Result) {
  550. Error (TEXT("Failed to write DllRangeStart value: error %u"), Result);
  551. }
  552. Result = RegSetValueEx (
  553. Key, TEXT ("PageHeapDllRangeEnd"), 0, REG_DWORD,
  554. (LPBYTE)(&RangeEnd), sizeof RangeEnd);
  555. if (Result) {
  556. Error (TEXT("Failed to write DllRangeStart value: error %u"), Result);
  557. }
  558. }
  559. if (LeakDetectionEnabled) {
  560. printf("/address option disabled because /leaks is present. \n");
  561. }
  562. }
  563. //
  564. // Check /random option
  565. //
  566. Option = SearchOption (Args, "/random");
  567. if (!LeakDetectionEnabled && Option != NULL) {
  568. if (Option[1]) {
  569. DWORD Probability;
  570. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  571. HeapFlags |= PAGE_HEAP_USE_RANDOM_DECISION;
  572. Scanned = sscanf (Option[1], "%u", &Probability);
  573. if (Scanned != 1) {
  574. Error (TEXT("Failed to read probability value."));
  575. }
  576. Result = RegSetValueEx (
  577. Key, TEXT ("PageHeapRandomProbability"), 0, REG_DWORD,
  578. (LPBYTE)(&Probability), sizeof Probability);
  579. if (Result) {
  580. Error (TEXT("Failed to write RandomProbability value: error %u"), Result);
  581. }
  582. }
  583. }
  584. if (Option && LeakDetectionEnabled) {
  585. printf("/random option disabled because /leaks is present. \n");
  586. }
  587. //
  588. // Check /fault option
  589. //
  590. Option = SearchOption (Args, "/fault");
  591. if (Option != NULL) {
  592. if (Option[1]) { // FAULT-RATE
  593. DWORD Probability;
  594. HeapFlags |= PAGE_HEAP_USE_FAULT_INJECTION;
  595. Scanned = sscanf (Option[1], "%u", &Probability);
  596. if (Scanned != 1) {
  597. Error (TEXT("Failed to read probability value."));
  598. }
  599. Result = RegSetValueEx (
  600. Key, TEXT ("PageHeapFaultProbability"), 0, REG_DWORD,
  601. (LPBYTE)(&Probability), sizeof Probability);
  602. if (Result) {
  603. Error (TEXT("Failed to write FaultProbability value: error %u"), Result);
  604. }
  605. if (Option[2]) { // TIME-OUT
  606. DWORD TimeOut;
  607. Scanned = sscanf (Option[2], "%u", &TimeOut);
  608. if (Scanned != 1) {
  609. Error (TEXT("Failed to read timeout value."));
  610. }
  611. Result = RegSetValueEx (
  612. Key, TEXT ("PageHeapFaultTimeOut"), 0, REG_DWORD,
  613. (LPBYTE)(&TimeOut), sizeof TimeOut);
  614. if (Result) {
  615. Error (TEXT("Failed to write FaultTimeOut value: error %u"), Result);
  616. }
  617. }
  618. }
  619. }
  620. //
  621. // Check /dlls option
  622. //
  623. Option = SearchOption (Args, "/dlls");
  624. if (!LeakDetectionEnabled && Option != NULL) {
  625. TCHAR Dlls[512];
  626. ULONG Index;
  627. if (Option[1]) {
  628. HeapFlags |= PAGE_HEAP_ENABLE_PAGE_HEAP;
  629. HeapFlags |= PAGE_HEAP_USE_DLL_NAMES;
  630. for (Index = 1, Dlls[0] = '\0';
  631. Option[Index] && Option[Index][0] != '/';
  632. Index++) {
  633. _tcscat (Dlls, Option[Index]);
  634. _tcscat (Dlls, " ");
  635. //
  636. // We do not allow more than 200 characters because this
  637. // will cause an overflow in \nt\base\ntdll\ldrinit.c in the
  638. // function that reads registry options.
  639. //
  640. if (_tcslen (Dlls) > 200) {
  641. break;
  642. }
  643. }
  644. //
  645. // SilviuC: the call to _tcslen below is not correct if we
  646. // ever will want to make this program Unicode.
  647. //
  648. Result = RegSetValueEx (
  649. Key, TEXT ("PageHeapTargetDlls"), 0, REG_SZ,
  650. (LPBYTE)(Dlls), (ULONG)_tcslen(Dlls) + 1);
  651. if (Result) {
  652. Error (TEXT("Failed to write RandomProbability value: error %u"), Result);
  653. }
  654. }
  655. }
  656. if (Option && LeakDetectionEnabled) {
  657. printf("/dlls option disabled because /leaks is present. \n");
  658. }
  659. //
  660. // Finally write the page heap flags value.
  661. //
  662. {
  663. TCHAR ValueBuffer [32];
  664. sprintf (ValueBuffer, "0x%x", HeapFlags);
  665. if (WriteHeapFlagValue (Key, ValueBuffer, (ULONG)_tcslen(ValueBuffer)) == FALSE) {
  666. Error (TEXT("Failed to write PageHeapFlags value."));
  667. }
  668. }
  669. CloseImageKey (Key);
  670. return TRUE;
  671. }
  672. BOOL
  673. DisablePageHeap (
  674. LPCTSTR Name)
  675. {
  676. HKEY Key;
  677. TCHAR Buffer [128];
  678. DWORD Flags;
  679. if ((Key = OpenImageKey (Name, TRUE)) == NULL) {
  680. //
  681. // There is no key therefore nothing to disable.
  682. //
  683. return TRUE;
  684. }
  685. if (ReadGlobalFlagValue (Key, Buffer, sizeof Buffer) == FALSE) {
  686. Flags = 0;
  687. }
  688. else {
  689. if (_stscanf (Buffer, TEXT("%x"), &Flags) != 1) {
  690. Flags = 0;
  691. }
  692. }
  693. Flags &= ~PAGE_HEAP_BIT;
  694. _stprintf (Buffer, TEXT("0x%08X"), Flags);
  695. //
  696. // If by wiping the page heap bit from `GlobalFlags' we get a zero
  697. // value we will wipe out the value altogether. This is important
  698. // when we run the app under debugger. In this case it makes a
  699. // difference if the value is not there or is all zeroes.
  700. //
  701. if (Flags != 0) {
  702. if (WriteGlobalFlagValue (Key, Buffer, (ULONG)_tcslen(Buffer)) == FALSE) {
  703. return FALSE;
  704. }
  705. }
  706. else {
  707. RegDeleteValue (Key, TEXT ("GlobalFlag"));
  708. }
  709. RegDeleteValue (Key, TEXT ("PageHeapFlags"));
  710. RegDeleteValue (Key, TEXT ("Debugger"));
  711. RegDeleteValue (Key, TEXT ("ShutdownFlags"));
  712. RegDeleteValue (Key, TEXT ("PageHeapSizeRangeStart"));
  713. RegDeleteValue (Key, TEXT ("PageHeapSizeRangeEnd"));
  714. RegDeleteValue (Key, TEXT ("PageHeapDllRangeStart"));
  715. RegDeleteValue (Key, TEXT ("PageHeapDllRangeEnd"));
  716. RegDeleteValue (Key, TEXT ("PageHeapTargetDlls"));
  717. RegDeleteValue (Key, TEXT ("PageHeapRandomProbability"));
  718. RegDeleteValue (Key, TEXT ("PageHeapFaultProbability"));
  719. RegDeleteValue (Key, TEXT ("PageHeapFaultTimeOut"));
  720. CloseImageKey (Key);
  721. return TRUE;
  722. }
  723. BOOL
  724. ReadGlobalFlagValue (
  725. HKEY Key,
  726. LPTSTR Buffer,
  727. ULONG Length)
  728. {
  729. LONG Result;
  730. DWORD Type;
  731. DWORD ReadLength = Length;
  732. Result = RegQueryValueEx (
  733. Key,
  734. TEXT ("GlobalFlag"),
  735. 0,
  736. &Type,
  737. (LPBYTE)Buffer,
  738. &ReadLength);
  739. if (Result != ERROR_SUCCESS || Type != REG_SZ) {
  740. return FALSE;
  741. }
  742. else {
  743. return TRUE;
  744. }
  745. }
  746. BOOL
  747. ReadHeapFlagValue (
  748. HKEY Key,
  749. LPTSTR Buffer,
  750. ULONG Length)
  751. {
  752. LONG Result;
  753. DWORD Type;
  754. DWORD ReadLength = Length;
  755. Result = RegQueryValueEx (
  756. Key,
  757. TEXT ("PageHeapFlags"),
  758. 0,
  759. &Type,
  760. (LPBYTE)Buffer,
  761. &ReadLength);
  762. if (Result != ERROR_SUCCESS || Type != REG_SZ) {
  763. return FALSE;
  764. }
  765. else {
  766. return TRUE;
  767. }
  768. }
  769. BOOL
  770. WriteGlobalFlagValue (
  771. HKEY Key,
  772. LPTSTR Buffer,
  773. ULONG Length)
  774. {
  775. LONG Result;
  776. Result = RegSetValueEx (
  777. Key,
  778. TEXT ("GlobalFlag"),
  779. 0,
  780. REG_SZ,
  781. (LPBYTE)Buffer,
  782. Length);
  783. if (Result != ERROR_SUCCESS) {
  784. return FALSE;
  785. }
  786. else {
  787. return TRUE;
  788. }
  789. }
  790. BOOL
  791. WriteHeapFlagValue (
  792. HKEY Key,
  793. LPTSTR Buffer,
  794. ULONG Length)
  795. {
  796. LONG Result;
  797. Result = RegSetValueEx (
  798. Key,
  799. TEXT ("PageHeapFlags"),
  800. 0,
  801. REG_SZ,
  802. (LPBYTE)Buffer,
  803. Length);
  804. if (Result != ERROR_SUCCESS) {
  805. return FALSE;
  806. }
  807. else {
  808. return TRUE;
  809. }
  810. }
  811. BOOL
  812. WriteDebuggerValue (
  813. HKEY Key,
  814. LPTSTR Buffer,
  815. ULONG Length)
  816. {
  817. LONG Result;
  818. Result = RegSetValueEx (
  819. Key,
  820. TEXT ("Debugger"),
  821. 0,
  822. REG_SZ,
  823. (LPBYTE)Buffer,
  824. Length);
  825. if (Result != ERROR_SUCCESS) {
  826. return FALSE;
  827. }
  828. else {
  829. return TRUE;
  830. }
  831. }
  832. BOOL
  833. IsShutdownFlagsValueDefined (
  834. LPCTSTR KeyName
  835. )
  836. {
  837. HKEY Key;
  838. LONG Result;
  839. DWORD Value;
  840. DWORD Type;
  841. DWORD ReadLength = sizeof (DWORD);
  842. if ((Key = OpenImageKey (KeyName, TRUE)) == NULL) {
  843. return FALSE;
  844. }
  845. Result = RegQueryValueEx (
  846. Key,
  847. TEXT ("ShutdownFlags"),
  848. 0,
  849. &Type,
  850. (LPBYTE)(&Value),
  851. &ReadLength);
  852. CloseImageKey (Key);
  853. if (Result == ERROR_SUCCESS && (Value & 0x03) == 0x03) {
  854. return TRUE;
  855. }
  856. else {
  857. return FALSE;
  858. }
  859. }
  860. HKEY
  861. OpenImageKey (
  862. LPCTSTR Name,
  863. BOOL ShouldExist)
  864. {
  865. HKEY Key;
  866. LONG Result;
  867. TCHAR Buffer [MAX_PATH];
  868. _stprintf (
  869. Buffer,
  870. TEXT ("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s"),
  871. Name);
  872. if (ShouldExist) {
  873. Result = RegOpenKeyEx (
  874. HKEY_LOCAL_MACHINE,
  875. Buffer,
  876. 0,
  877. KEY_ALL_ACCESS,
  878. &Key);
  879. }
  880. else {
  881. Result = RegCreateKeyEx (
  882. HKEY_LOCAL_MACHINE,
  883. Buffer,
  884. 0,
  885. 0,
  886. 0,
  887. KEY_ALL_ACCESS,
  888. NULL,
  889. &Key,
  890. NULL);
  891. }
  892. if (Result != ERROR_SUCCESS) {
  893. return NULL;
  894. }
  895. else {
  896. return Key;
  897. }
  898. }
  899. VOID
  900. CloseImageKey (
  901. HKEY Key)
  902. {
  903. RegCloseKey (Key);
  904. }
  905. VOID
  906. CreateImageName (
  907. LPCTSTR Source,
  908. LPTSTR Name,
  909. ULONG Length)
  910. {
  911. //
  912. // Length is MAX_PATH + 1 so that it can accomodate MAX_PATH
  913. // characters and a null termination character.
  914. //
  915. _tcsncpy (Name, Source, Length - 1);
  916. Name[Length - 1] = L'\0';
  917. _tcslwr (Name);
  918. }
  919. VOID
  920. PrintPageheapEnabledApplications (
  921. )
  922. {
  923. LPCTSTR ImageFileExecutionOptionsKeyName =
  924. TEXT ("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options");
  925. HKEY OptionsKey;
  926. LONG Result;
  927. TCHAR KeyName [MAX_PATH];
  928. ULONG KeySize;
  929. BOOL FoundOne = FALSE;
  930. ULONG Index;
  931. FILETIME FileTime;
  932. Result = RegOpenKeyEx (
  933. HKEY_LOCAL_MACHINE,
  934. ImageFileExecutionOptionsKeyName,
  935. 0,
  936. KEY_ALL_ACCESS,
  937. &OptionsKey);
  938. if (Result != ERROR_SUCCESS) {
  939. Error (TEXT("Cannot open registry key %s: error %u"),
  940. ImageFileExecutionOptionsKeyName,
  941. Result);
  942. }
  943. for (Index = 0; ; Index += 1) {
  944. KeySize = MAX_PATH;
  945. Result = RegEnumKeyEx (
  946. OptionsKey,
  947. Index,
  948. KeyName,
  949. &KeySize,
  950. NULL,
  951. NULL,
  952. NULL,
  953. &FileTime);
  954. if (Result == ERROR_NO_MORE_ITEMS) {
  955. break;
  956. }
  957. if (Result != ERROR_SUCCESS) {
  958. Error (TEXT("Cannot enumerate registry key %s: error %u"),
  959. ImageFileExecutionOptionsKeyName,
  960. Result);
  961. }
  962. if (IsPageHeapEnabled (KeyName)) {
  963. DWORD Value;
  964. FoundOne = TRUE;
  965. if (IsPageHeapFlagsValueDefined (KeyName, &Value)) {
  966. _tprintf (TEXT("%s: page heap enabled with flags ("), KeyName);
  967. PrintFlags (Value, IsShutdownFlagsValueDefined(KeyName));
  968. _tprintf (TEXT(")\n"));
  969. }
  970. else {
  971. _tprintf (TEXT("%s: page heap enabled with flags ("), KeyName);
  972. PrintFlags (0, IsShutdownFlagsValueDefined(KeyName));
  973. _tprintf (TEXT(")\n"));
  974. }
  975. }
  976. }
  977. if (FoundOne == FALSE) {
  978. _tprintf (TEXT("No application has page heap enabled.\n"));
  979. }
  980. }
  981. BOOL
  982. IsWow64Active (
  983. )
  984. {
  985. ULONG_PTR ul;
  986. NTSTATUS st;
  987. //
  988. // If this call succeeds then we are on Windows 2000 or later.
  989. //
  990. st = NtQueryInformationProcess(NtCurrentProcess(),
  991. ProcessWow64Information,
  992. &ul,
  993. sizeof(ul),
  994. NULL);
  995. if (NT_SUCCESS(st) && (0 != ul)) {
  996. // 32-bit code running on Win64
  997. return TRUE;
  998. }
  999. else {
  1000. return FALSE;
  1001. }
  1002. }