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.

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