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.

1331 lines
77 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. extinit.c
  5. Abstract:
  6. This file implements all the initialization library routines operating on
  7. extensible performance libraries.
  8. Author:
  9. JeePang
  10. Revision History:
  11. 09/27/2000 - JeePang - Moved from perflib.c
  12. --*/
  13. #define UNICODE
  14. //
  15. // Include files
  16. //
  17. #pragma warning(disable:4306)
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <ntregapi.h>
  22. #include <ntprfctr.h>
  23. #include <windows.h>
  24. #include <string.h>
  25. #include <stdlib.h>
  26. #include <winperf.h>
  27. #include <rpc.h>
  28. #include "regrpc.h"
  29. #include "ntconreg.h"
  30. #include "prflbmsg.h" // event log messages
  31. #include "perflib.h"
  32. #pragma warning(default:4306)
  33. //
  34. // static constant definitions
  35. //
  36. // constants used by guard page testing
  37. //
  38. #define GUARD_PAGE_SIZE 1024
  39. #define GUARD_PAGE_CHAR 0xA5
  40. #define GUARD_PAGE_DWORD 0xA5A5A5A5
  41. typedef struct _EXT_OBJ_ITEM {
  42. DWORD dwObjId;
  43. DWORD dwFlags;
  44. } EXT_OBJ_LIST, *PEXT_OBJ_LIST;
  45. #define PERF_EOL_ITEM_FOUND ((DWORD)0x00000001)
  46. __inline
  47. DWORD
  48. RegisterExtObjListAccess ()
  49. {
  50. LONG Status;
  51. LARGE_INTEGER liWaitTime;
  52. if (hGlobalDataMutex != NULL) {
  53. liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  54. // wait for access to the list of ext objects
  55. Status = NtWaitForSingleObject (
  56. hGlobalDataMutex,
  57. FALSE,
  58. &liWaitTime);
  59. if (Status != WAIT_TIMEOUT) {
  60. if (hExtObjListIsNotInUse != NULL) {
  61. // indicate that we are going to use the list
  62. InterlockedIncrement ((LONG *)&dwExtObjListRefCount);
  63. if (dwExtObjListRefCount > 0) {
  64. ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
  65. } else {
  66. SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
  67. }
  68. Status = ERROR_SUCCESS;
  69. } else {
  70. Status = ERROR_NOT_READY;
  71. }
  72. ReleaseMutex (hGlobalDataMutex);
  73. } // else return status;
  74. } else {
  75. Status = ERROR_LOCK_FAILED;
  76. }
  77. return Status;
  78. }
  79. __inline
  80. DWORD
  81. DeRegisterExtObjListAccess ()
  82. {
  83. LONG Status;
  84. LARGE_INTEGER liWaitTime;
  85. if (hGlobalDataMutex != NULL) {
  86. liWaitTime.QuadPart = MakeTimeOutValue(QUERY_WAIT_TIME);
  87. // wait for access to the list of ext objects
  88. Status = NtWaitForSingleObject (
  89. hGlobalDataMutex,
  90. FALSE,
  91. &liWaitTime);
  92. if (Status != WAIT_TIMEOUT) {
  93. if (hExtObjListIsNotInUse != NULL) {
  94. assert (dwExtObjListRefCount > 0);
  95. // indicate that we are going to use the list
  96. InterlockedDecrement ((LONG *)&dwExtObjListRefCount);
  97. if (dwExtObjListRefCount > 0) {
  98. ResetEvent (hExtObjListIsNotInUse); // indicate list is busy
  99. } else {
  100. SetEvent (hExtObjListIsNotInUse); // indicate list is not busy
  101. }
  102. Status = ERROR_SUCCESS;
  103. } else {
  104. Status = ERROR_NOT_READY;
  105. }
  106. ReleaseMutex (hGlobalDataMutex);
  107. } // else return status;
  108. } else {
  109. Status = ERROR_LOCK_FAILED;
  110. }
  111. return Status;
  112. }
  113. LONG
  114. QueryExtensibleData (
  115. COLLECT_THREAD_DATA * pArgs
  116. )
  117. /*++
  118. QueryExtensibleData - Get data from extensible objects
  119. Inputs:
  120. dwQueryType - Query type (GLOBAL, COSTLY, item list, etc.)
  121. lpValueName - pointer to value string (unused)
  122. lpData - pointer to start of data block
  123. where data is being collected
  124. lpcbData - pointer to size of data buffer
  125. lppDataDefinition - pointer to pointer to where object
  126. definition for this object type should
  127. go
  128. Outputs:
  129. *lppDataDefinition - set to location for next Type
  130. Definition if successful
  131. Returns:
  132. 0 if successful, else Win 32 error code of failure
  133. --*/
  134. {
  135. DWORD dwQueryType = pArgs->dwQueryType;
  136. LPWSTR lpValueName = pArgs->lpValueName;
  137. LPBYTE lpData = pArgs->lpData;
  138. LPDWORD lpcbData = pArgs->lpcbData;
  139. LPVOID *lppDataDefinition = pArgs->lppDataDefinition;
  140. DWORD Win32Error=ERROR_SUCCESS; // Failure code
  141. DWORD BytesLeft;
  142. DWORD InitialBytesLeft;
  143. DWORD NumObjectTypes;
  144. LPVOID lpExtDataBuffer = NULL;
  145. LPVOID lpCallBuffer = NULL;
  146. LPVOID lpLowGuardPage = NULL;
  147. LPVOID lpHiGuardPage = NULL;
  148. LPVOID lpEndPointer = NULL;
  149. LPVOID lpBufferBefore = NULL;
  150. LPVOID lpBufferAfter = NULL;
  151. PUCHAR lpCheckPointer;
  152. LARGE_INTEGER liStartTime, liEndTime, liWaitTime, liDiff;
  153. PEXT_OBJECT pThisExtObj = NULL;
  154. DWORD dwLibEntry;
  155. BOOL bGuardPageOK;
  156. BOOL bBufferOK;
  157. BOOL bException;
  158. BOOL bUseSafeBuffer;
  159. BOOL bUnlockObjData = FALSE;
  160. LPTSTR szMessageArray[8];
  161. ULONG_PTR dwRawDataDwords[8]; // raw data buffer
  162. DWORD dwDataIndex;
  163. WORD wStringIndex;
  164. LONG lReturnValue = ERROR_SUCCESS;
  165. LONG lDllTestLevel;
  166. LONG lInstIndex;
  167. DWORD lCtrIndex;
  168. PERF_OBJECT_TYPE *pObject, *pNextObject;
  169. PERF_INSTANCE_DEFINITION *pInstance;
  170. PERF_COUNTER_DEFINITION *pCounterDef;
  171. PERF_DATA_BLOCK *pPerfData;
  172. BOOL bForeignDataBuffer;
  173. DWORD dwItemsInArray = 0;
  174. DWORD dwItemsInList = 0;
  175. volatile PEXT_OBJ_LIST pQueryList = NULL;
  176. LPWSTR pwcThisChar;
  177. DWORD dwThisNumber;
  178. DWORD dwIndex, dwEntry;
  179. BOOL bFound;
  180. BOOL bDisabled = FALSE;
  181. BOOL bUseTimer;
  182. DWORD dwType = 0;
  183. DWORD dwValue = 0;
  184. DWORD dwSize = sizeof(DWORD);
  185. DWORD status = 0;
  186. DWORD dwObjectBufSize;
  187. OPEN_PROC_WAIT_INFO opwInfo;
  188. HANDLE hPerflibFuncTimer;
  189. PVOID pNewBuffer;
  190. HEAP_PROBE();
  191. //
  192. // Make sure that the caller's buffer is aligned properly
  193. //
  194. #ifdef _WIN64
  195. if ((ULONG_PTR) *lppDataDefinition & (ULONG_PTR) 0x07) {
  196. DebugPrint((0, "QueryExtensibleData: lppDataDefinition not aligned %I64x\n", lppDataDefinition));
  197. return ERROR_INVALID_USER_BUFFER;
  198. }
  199. /*
  200. if ((ULONG_PTR) *lpcbData & (ULONG_PTR) 0x07) {
  201. DebugPrint((0, "QueryExtensibleData: lpcbData not aligned %I64x\n", *lpcbData));
  202. return ERROR_INVALID_USER_BUFFER;
  203. }
  204. */
  205. if ((ULONG_PTR) lpData & (ULONG_PTR) 0x07) {
  206. DebugPrint((0, "QueryExtensibleData: lpData not aligned %I64x\n", lpData));
  207. return ERROR_INVALID_USER_BUFFER;
  208. }
  209. #endif
  210. // see if perf data has been disabled
  211. // this is to prevent crashing WINLOGON if the
  212. // system has installed a bogus DLL
  213. if (ghKeyPerflib == NULL || ghKeyPerflib == INVALID_HANDLE_VALUE) {
  214. // Ignore Status return. We only need ghKeyPerflib to query "DisablePerformanceCounters" DWORD value.
  215. //
  216. HKEY lhKeyPerflib = NULL;
  217. status = (DWORD) RegOpenKeyExW(HKEY_LOCAL_MACHINE, HKLMPerflibKey, 0L, KEY_READ, & lhKeyPerflib);
  218. if (status == ERROR_SUCCESS) {
  219. if (InterlockedCompareExchangePointer(& ghKeyPerflib, lhKeyPerflib, NULL) != NULL) {
  220. RegCloseKey(lhKeyPerflib);
  221. lhKeyPerflib = NULL;
  222. }
  223. }
  224. }
  225. assert (ghKeyPerflib != NULL);
  226. dwSize = sizeof(dwValue);
  227. dwValue = dwType = 0;
  228. if (ghKeyPerflib != NULL && ghKeyPerflib != INVALID_HANDLE_VALUE) {
  229. status = PrivateRegQueryValueExW(
  230. ghKeyPerflib,
  231. DisablePerformanceCounters,
  232. NULL,
  233. & dwType,
  234. (LPBYTE) & dwValue,
  235. & dwSize);
  236. if (status == ERROR_SUCCESS && dwType == REG_DWORD && dwValue == 1) {
  237. // then DON'T Load any libraries and unload any that have been
  238. // loaded
  239. bDisabled = TRUE;
  240. }
  241. }
  242. // if data collection is disabled and there's a collection thread
  243. // then close it
  244. if (bDisabled && (hCollectThread != NULL)) {
  245. pArgs->dwActionFlags = CTD_AF_CLOSE_THREAD;
  246. } else if (!bDisabled &&
  247. ((hCollectThread == NULL) && (dwCollectionFlags == COLL_FLAG_USE_SEPARATE_THREAD))) {
  248. // then data collection is enabled and they want a separate collection
  249. // thread, but there's no thread at the moment, so create it here
  250. pArgs->dwActionFlags = CTD_AF_OPEN_THREAD;
  251. }
  252. lReturnValue = RegisterExtObjListAccess();
  253. if (lReturnValue == ERROR_SUCCESS) {
  254. liStartTime.QuadPart = 0;
  255. InitialBytesLeft = 0;
  256. liEndTime.QuadPart = 0;
  257. if ((dwQueryType == QUERY_ITEMS) && (!bDisabled)) {
  258. // alloc the call list
  259. pwcThisChar = lpValueName;
  260. dwThisNumber = 0;
  261. // read the value string and build an object ID list
  262. while (*pwcThisChar != 0) {
  263. dwThisNumber = GetNextNumberFromList (
  264. pwcThisChar, &pwcThisChar);
  265. if (dwThisNumber != 0) {
  266. if (dwItemsInList >= dwItemsInArray) {
  267. dwItemsInArray += 16; // starting point for # of objects
  268. pNewBuffer = NULL;
  269. if (pQueryList == NULL) {
  270. // alloc a new buffer
  271. pNewBuffer = ALLOCMEM ((sizeof(EXT_OBJ_LIST) * dwItemsInArray));
  272. } else {
  273. // realloc a new buffer
  274. pNewBuffer = REALLOCMEM(pQueryList,
  275. (sizeof(EXT_OBJ_LIST) * dwItemsInArray));
  276. }
  277. if (pNewBuffer == NULL) {
  278. // unable to alloc memory so bail
  279. if (pQueryList)
  280. FREEMEM(pQueryList);
  281. return ERROR_OUTOFMEMORY;
  282. }
  283. else {
  284. pQueryList = pNewBuffer;
  285. }
  286. }
  287. // then add to the list
  288. pQueryList[dwItemsInList].dwObjId = dwThisNumber;
  289. pQueryList[dwItemsInList].dwFlags = 0;
  290. dwItemsInList++;
  291. }
  292. }
  293. if (Win32Error == ERROR_SUCCESS) {
  294. //
  295. // Walk through list of ext. objects and tag the ones to call
  296. // as the query objects are found
  297. //
  298. for (pThisExtObj = ExtensibleObjects, dwLibEntry = 0;
  299. pThisExtObj != NULL;
  300. pThisExtObj = pThisExtObj->pNext, dwLibEntry++) {
  301. if (pThisExtObj->dwNumObjects > 0) {
  302. // then examine list
  303. for (dwIndex = 0; dwIndex < pThisExtObj->dwNumObjects; dwIndex++) {
  304. // look at each entry in the list
  305. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  306. if (pQueryList[dwEntry].dwObjId == pThisExtObj->dwObjList[dwIndex]) {
  307. // tag this entry as found
  308. pQueryList[dwEntry].dwFlags |= PERF_EOL_ITEM_FOUND;
  309. // tag the object as needed
  310. pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
  311. }
  312. }
  313. }
  314. } else {
  315. // this entry doesn't list it's supported objects
  316. }
  317. }
  318. assert (dwLibEntry == NumExtensibleObjects);
  319. // see if any in the query list do not have entries
  320. bFound = TRUE;
  321. for (dwEntry = 0; dwEntry < dwItemsInList; dwEntry++) {
  322. if (!(pQueryList[dwEntry].dwFlags & PERF_EOL_ITEM_FOUND)) {
  323. // no matching object found
  324. bFound = FALSE;
  325. break;
  326. }
  327. }
  328. if (!bFound) {
  329. // at least one of the object ID's in the query list was
  330. // not found in an object that supports an object list
  331. // then tag all entries that DO NOT support an object list
  332. // to be called and hope one of them supports it/them.
  333. for (pThisExtObj = ExtensibleObjects;
  334. pThisExtObj != NULL;
  335. pThisExtObj = pThisExtObj->pNext) {
  336. if (pThisExtObj->dwNumObjects == 0) {
  337. // tag this one so it will be called
  338. pThisExtObj->dwFlags |= PERF_EO_OBJ_IN_QUERY;
  339. }
  340. }
  341. }
  342. } // end if first scan was successful
  343. if (pQueryList != NULL) FREEMEM (pQueryList);
  344. } // end if QUERY_ITEMS
  345. if (lReturnValue == ERROR_SUCCESS) {
  346. for (pThisExtObj = ExtensibleObjects;
  347. pThisExtObj != NULL;
  348. pThisExtObj = pThisExtObj->pNext) {
  349. // set the current ext object pointer
  350. pArgs->pCurrentExtObject = pThisExtObj;
  351. // convert timeout value
  352. liWaitTime.QuadPart = MakeTimeOutValue (pThisExtObj->dwCollectTimeout);
  353. // close the unused Perf DLL's IF:
  354. // the perflib key is disabled or this is an item query
  355. // and this is an Item (as opposed to a global or foreign) query or
  356. // the requested objects are not it this library or this library is disabled
  357. // and this library has been opened
  358. //
  359. if (((dwQueryType == QUERY_ITEMS) || bDisabled) &&
  360. (bDisabled || (!(pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY)) || (pThisExtObj->dwFlags & PERF_EO_DISABLED)) &&
  361. (pThisExtObj->hLibrary != NULL)) {
  362. // then free this object
  363. if (pThisExtObj->hMutex != NULL) {
  364. NTSTATUS NtStatus = NtWaitForSingleObject (
  365. pThisExtObj->hMutex,
  366. FALSE,
  367. &liWaitTime);
  368. Win32Error = PerfpDosError(NtStatus);
  369. if (NtStatus == STATUS_SUCCESS) {
  370. // then we got a lock
  371. CloseExtObjectLibrary (pThisExtObj, bDisabled);
  372. ReleaseMutex (pThisExtObj->hMutex);
  373. } else {
  374. pThisExtObj->dwLockoutCount++;
  375. DebugPrint((0, "Unable to Lock object for %ws to close in Query\n", pThisExtObj->szServiceName));
  376. }
  377. } else {
  378. Win32Error = ERROR_LOCK_FAILED;
  379. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  380. }
  381. if (hCollectThread != NULL) {
  382. // close the collection thread
  383. }
  384. } else if (((dwQueryType == QUERY_FOREIGN) ||
  385. (dwQueryType == QUERY_GLOBAL) ||
  386. (dwQueryType == QUERY_COSTLY) ||
  387. ((dwQueryType == QUERY_ITEMS) &&
  388. (pThisExtObj->dwFlags & PERF_EO_OBJ_IN_QUERY))) &&
  389. (!(pThisExtObj->dwFlags & PERF_EO_DISABLED))) {
  390. // initialize values to pass to the extensible counter function
  391. NumObjectTypes = 0;
  392. BytesLeft = (DWORD) (*lpcbData - ((LPBYTE) *lppDataDefinition - lpData));
  393. bException = FALSE;
  394. if ((pThisExtObj->hLibrary == NULL) ||
  395. (dwQueryType == QUERY_GLOBAL) ||
  396. (dwQueryType == QUERY_COSTLY)) {
  397. // lock library object
  398. if (pThisExtObj->hMutex != NULL) {
  399. NTSTATUS NtStatus = NtWaitForSingleObject (
  400. pThisExtObj->hMutex,
  401. FALSE,
  402. &liWaitTime);
  403. Win32Error = ERROR_SUCCESS;
  404. if (NtStatus == STATUS_SUCCESS) {
  405. // if this is a global or costly query, then reset the "in query"
  406. // flag for this object. The next ITEMS query will restore it.
  407. if ((dwQueryType == QUERY_GLOBAL) ||
  408. (dwQueryType == QUERY_COSTLY)) {
  409. pThisExtObj->dwFlags &= ~PERF_EO_OBJ_IN_QUERY;
  410. }
  411. // if necessary, open the library
  412. if (pThisExtObj->hLibrary == NULL) {
  413. if ((GetCurrentThreadId() != pThisExtObj->ThreadId) &&
  414. (pThisExtObj->dwOpenFail == 0)) {
  415. // make sure the library is open
  416. Win32Error = OpenExtObjectLibrary(pThisExtObj);
  417. if (Win32Error != ERROR_SUCCESS) {
  418. #if DBG
  419. if (Win32Error != ERROR_SERVICE_DISABLED) {
  420. // SERVICE_DISABLED is returned when the
  421. // service has been disabled via ExCtrLst.
  422. // so no point in complaining about it.
  423. // assume error has been posted
  424. DebugPrint((0, "Unable to open perf counter library for %ws, Error: 0x%8.8x\n",
  425. pThisExtObj->szServiceName, Win32Error));
  426. }
  427. #endif
  428. ReleaseMutex (pThisExtObj->hMutex);
  429. continue; // to next entry
  430. }
  431. }
  432. else {
  433. ReleaseMutex (pThisExtObj->hMutex);
  434. continue; // to next entry
  435. }
  436. }
  437. ReleaseMutex (pThisExtObj->hMutex);
  438. } else {
  439. Win32Error = PerfpDosError(NtStatus);
  440. pThisExtObj->dwLockoutCount++;
  441. DebugPrint((0, "Unable to Lock object for %ws to open for Query\n", pThisExtObj->szServiceName));
  442. }
  443. } else {
  444. Win32Error = ERROR_LOCK_FAILED;
  445. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  446. }
  447. } else {
  448. // library should be ready to use
  449. }
  450. // if this dll is trusted, then use the system
  451. // defined test level, otherwise, test it
  452. // thorourghly
  453. bUseTimer = TRUE; // default
  454. if (!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) {
  455. if (pThisExtObj->dwFlags & PERF_EO_TRUSTED) {
  456. lDllTestLevel = lExtCounterTestLevel;
  457. bUseTimer = FALSE; // Trusted DLL's are not timed
  458. } else {
  459. // not trusted so use full test
  460. lDllTestLevel = EXT_TEST_ALL;
  461. }
  462. } else {
  463. // disable DLL testing
  464. lDllTestLevel = EXT_TEST_NOMEMALLOC;
  465. bUseTimer = FALSE; // Timing is disabled as well
  466. }
  467. if (lDllTestLevel < EXT_TEST_NOMEMALLOC) {
  468. bUseSafeBuffer = TRUE;
  469. } else {
  470. bUseSafeBuffer = FALSE;
  471. }
  472. // allocate a local block of memory to pass to the
  473. // extensible counter function.
  474. if (bUseSafeBuffer) {
  475. lpExtDataBuffer = ALLOCMEM (BytesLeft + (2*GUARD_PAGE_SIZE));
  476. } else {
  477. lpExtDataBuffer =
  478. lpCallBuffer = *lppDataDefinition;
  479. }
  480. if (lpExtDataBuffer != NULL) {
  481. if (bUseSafeBuffer) {
  482. // set buffer pointers
  483. lpLowGuardPage = lpExtDataBuffer;
  484. lpCallBuffer = (LPBYTE)lpExtDataBuffer + GUARD_PAGE_SIZE;
  485. lpHiGuardPage = (LPBYTE)lpCallBuffer + BytesLeft;
  486. lpEndPointer = (LPBYTE)lpHiGuardPage + GUARD_PAGE_SIZE;
  487. // initialize GuardPage Data
  488. memset (lpLowGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  489. memset (lpHiGuardPage, GUARD_PAGE_CHAR, GUARD_PAGE_SIZE);
  490. }
  491. lpBufferBefore = lpCallBuffer;
  492. lpBufferAfter = NULL;
  493. hPerflibFuncTimer = NULL;
  494. try {
  495. //
  496. // Collect data from extensible objects
  497. //
  498. if (pThisExtObj->hMutex != NULL) {
  499. NTSTATUS NtStatus = NtWaitForSingleObject (
  500. pThisExtObj->hMutex,
  501. FALSE,
  502. &liWaitTime);
  503. Win32Error = PerfpDosError(NtStatus);
  504. if ((NtStatus == STATUS_SUCCESS) &&
  505. (pThisExtObj->CollectProc != NULL)) {
  506. bUnlockObjData = TRUE;
  507. opwInfo.pNext = NULL;
  508. opwInfo.szLibraryName = pThisExtObj->szLibraryName;
  509. opwInfo.szServiceName = pThisExtObj->szServiceName;
  510. opwInfo.dwWaitTime = pThisExtObj->dwCollectTimeout;
  511. opwInfo.dwEventMsg = PERFLIB_COLLECTION_HUNG;
  512. opwInfo.pData = (LPVOID)pThisExtObj;
  513. if (bUseTimer) {
  514. hPerflibFuncTimer = StartPerflibFunctionTimer(&opwInfo);
  515. // if no timer, continue anyway, even though things may
  516. // hang, it's better than not loading the DLL since they
  517. // usually load OK
  518. //
  519. if (hPerflibFuncTimer == NULL) {
  520. // unable to get a timer entry
  521. DebugPrint((0, "Unable to acquire timer for Collect Proc\n"));
  522. }
  523. } else {
  524. hPerflibFuncTimer = NULL;
  525. }
  526. InitialBytesLeft = BytesLeft;
  527. NtQueryPerformanceCounter (&liStartTime, NULL);
  528. Win32Error = (*pThisExtObj->CollectProc) (
  529. lpValueName,
  530. &lpCallBuffer,
  531. &BytesLeft,
  532. &NumObjectTypes);
  533. NtQueryPerformanceCounter (&liEndTime, &liDiff);
  534. if (liDiff.QuadPart > 0) {
  535. liDiff.QuadPart = (liEndTime.QuadPart - liStartTime.QuadPart) /
  536. (liDiff.QuadPart / 1000) ;
  537. if ((liDiff.QuadPart > 100) || (Win32Error != ERROR_SUCCESS)) {
  538. TRACE((WINPERF_DBG_TRACE_INFO),
  539. (&PerflibGuid, __LINE__, PERF_QUERY_EXTDATA,
  540. ARG_DEF(ARG_TYPE_WSTR, 1) | ARG_DEF(ARG_TYPE_ULONG64, 2), Win32Error,
  541. pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
  542. liDiff, sizeof(liDiff), NULL));
  543. }
  544. }
  545. if (hPerflibFuncTimer != NULL) {
  546. // kill timer
  547. KillPerflibFunctionTimer (hPerflibFuncTimer);
  548. hPerflibFuncTimer = NULL;
  549. }
  550. // update statistics
  551. pThisExtObj->dwLastBufferSize = BytesLeft;
  552. if (BytesLeft > pThisExtObj->dwMaxBufferSize) {
  553. pThisExtObj->dwMaxBufferSize = BytesLeft;
  554. }
  555. if ((Win32Error == ERROR_MORE_DATA) &&
  556. (InitialBytesLeft > pThisExtObj->dwMaxBufferRejected)) {
  557. pThisExtObj->dwMaxBufferRejected = InitialBytesLeft;
  558. }
  559. lpBufferAfter = lpCallBuffer;
  560. pThisExtObj->llLastUsedTime = GetTimeAsLongLong();
  561. ReleaseMutex (pThisExtObj->hMutex);
  562. bUnlockObjData = FALSE;
  563. #if DBG
  564. if ( (((ULONG_PTR) lpCallBuffer) & 0x07) != 0) {
  565. DbgPrint("Perflib: Misaligned pointer %X returned from '%s'\n",
  566. lpCallBuffer, pThisExtObj->szLibraryName);
  567. // ASSERT( (((ULONG_PTR)lpCallBuffer) & 0x07) == 0);
  568. }
  569. #endif
  570. } else {
  571. if (pThisExtObj->CollectProc != NULL) {
  572. DebugPrint((0,
  573. "Unable to Lock object for %ws to Collect data\n",
  574. pThisExtObj->szServiceName));
  575. TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
  576. PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
  577. pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
  578. NULL));
  579. if (THROTTLE_PERFDLL(PERFLIB_COLLECTION_HUNG, pThisExtObj)) {
  580. dwDataIndex = wStringIndex = 0;
  581. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  582. dwRawDataDwords[dwDataIndex++] =
  583. (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  584. szMessageArray[wStringIndex++] =
  585. pThisExtObj->szServiceName;
  586. szMessageArray[wStringIndex++] =
  587. pThisExtObj->szLibraryName;
  588. ReportEvent (hEventLog,
  589. EVENTLOG_WARNING_TYPE, // error type
  590. 0, // category (not used)
  591. (DWORD)PERFLIB_COLLECTION_HUNG, // event,
  592. NULL, // SID (not used),
  593. wStringIndex, // number of strings
  594. dwDataIndex*sizeof(DWORD), // sizeof raw data
  595. szMessageArray, // message text array
  596. (LPVOID)&dwRawDataDwords[0]); // raw data
  597. }
  598. pThisExtObj->dwLockoutCount++;
  599. } else {
  600. // else it's not open so ignore.
  601. BytesLeft = 0;
  602. NumObjectTypes = 0;
  603. }
  604. }
  605. } else {
  606. Win32Error = ERROR_LOCK_FAILED;
  607. DebugPrint((0, "No Lock found for %ws\n", pThisExtObj->szServiceName));
  608. TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
  609. PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
  610. pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
  611. NULL));
  612. }
  613. if ((Win32Error == ERROR_SUCCESS) && (BytesLeft > 0)) {
  614. // increment perf counters
  615. if (BytesLeft > InitialBytesLeft) {
  616. TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
  617. PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
  618. pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
  619. BytesLeft, sizeof(DWORD), InitialBytesLeft, sizeof(DWORD),
  620. NULL));
  621. if (THROTTLE_PERFDLL(PERFLIB_INVALID_SIZE_RETURNED, pThisExtObj)) {
  622. // memory error
  623. dwDataIndex = wStringIndex = 0;
  624. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)InitialBytesLeft;
  625. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
  626. szMessageArray[wStringIndex++] =
  627. pThisExtObj->szServiceName;
  628. szMessageArray[wStringIndex++] =
  629. pThisExtObj->szLibraryName;
  630. ReportEvent (hEventLog,
  631. EVENTLOG_ERROR_TYPE, // error type
  632. 0, // category (not used)
  633. (DWORD)PERFLIB_INVALID_SIZE_RETURNED, // event,
  634. NULL, // SID (not used),
  635. wStringIndex, // number of strings
  636. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  637. szMessageArray, // message text array
  638. (LPVOID)&dwRawDataDwords[0]); // raw data
  639. }
  640. // disable the dll unless:
  641. // testing has been disabled.
  642. // or this is a trusted DLL (which are never disabled)
  643. // the event log message should be reported in any case since
  644. // this is a serious error
  645. //
  646. if ((!(lPerflibConfigFlags & PLCF_NO_DLL_TESTING)) &&
  647. (!(pThisExtObj->dwFlags & PERF_EO_TRUSTED))) {
  648. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  649. }
  650. // set error values to correct entries
  651. BytesLeft = 0;
  652. NumObjectTypes = 0;
  653. } else {
  654. // the buffer seems ok so far, so validate it
  655. InterlockedIncrement ((LONG *)&pThisExtObj->dwCollectCount);
  656. pThisExtObj->llElapsedTime +=
  657. liEndTime.QuadPart - liStartTime.QuadPart;
  658. // test all returned buffers for correct alignment
  659. if ((((ULONG_PTR)BytesLeft & (ULONG_PTR)0x07)) &&
  660. !(lPerflibConfigFlags & PLCF_NO_ALIGN_ERRORS)) {
  661. if (((pThisExtObj->dwFlags & PERF_EO_ALIGN_ERR_POSTED) == 0) &&
  662. THROTTLE_PERFDLL(PERFLIB_BUFFER_ALIGNMENT_ERROR, pThisExtObj)) {
  663. dwDataIndex = wStringIndex = 0;
  664. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)lpCallBuffer;
  665. dwRawDataDwords[dwDataIndex++] = (ULONG_PTR)BytesLeft;
  666. szMessageArray[wStringIndex++] =
  667. pThisExtObj->szServiceName;
  668. szMessageArray[wStringIndex++] =
  669. pThisExtObj->szLibraryName;
  670. ReportEvent (hEventLog,
  671. EVENTLOG_WARNING_TYPE, // error type
  672. 0, // category (not used)
  673. (DWORD)PERFLIB_BUFFER_ALIGNMENT_ERROR, // event,
  674. NULL, // SID (not used),
  675. wStringIndex, // number of strings
  676. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  677. szMessageArray, // message text array
  678. (LPVOID)&dwRawDataDwords[0]); // raw data
  679. pThisExtObj->dwFlags |= PERF_EO_ALIGN_ERR_POSTED;
  680. }
  681. #ifdef _WIN64
  682. // try and fix up BytesLeft and lpCallBuffer
  683. BytesLeft = ExtpAlignBuffer(lpBufferBefore,
  684. (PCHAR*) &lpCallBuffer, (InitialBytesLeft - BytesLeft));
  685. lpBufferAfter = lpCallBuffer;
  686. #endif
  687. }
  688. if (bUseSafeBuffer) {
  689. // a data buffer was returned and
  690. // the function returned OK so see how things
  691. // turned out...
  692. //
  693. //
  694. // check for buffer corruption here
  695. //
  696. bBufferOK = TRUE; // assume it's ok until a check fails
  697. //
  698. if (lDllTestLevel <= EXT_TEST_BASIC) {
  699. DWORD BytesAvailable;
  700. //
  701. // check 1: bytes left should be the same as
  702. // new data buffer ptr - orig data buffer ptr
  703. //
  704. BytesAvailable = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  705. if (BytesLeft != BytesAvailable) {
  706. if (THROTTLE_PERFDLL(PERFLIB_BUFFER_POINTER_MISMATCH, pThisExtObj)) {
  707. // issue WARNING, that bytes left param is incorrect
  708. // load data for eventlog message
  709. // this error is correctable
  710. dwDataIndex = wStringIndex = 0;
  711. dwRawDataDwords[dwDataIndex++] = BytesLeft;
  712. dwRawDataDwords[dwDataIndex++] = BytesAvailable;
  713. szMessageArray[wStringIndex++] =
  714. pThisExtObj->szServiceName;
  715. szMessageArray[wStringIndex++] =
  716. pThisExtObj->szLibraryName;
  717. ReportEvent (hEventLog,
  718. EVENTLOG_WARNING_TYPE, // error type
  719. 0, // category (not used)
  720. (DWORD)PERFLIB_BUFFER_POINTER_MISMATCH, // event,
  721. NULL, // SID (not used),
  722. wStringIndex, // number of strings
  723. dwDataIndex*sizeof(DWORD), // sizeof raw data
  724. szMessageArray, // message text array
  725. (LPVOID)&dwRawDataDwords[0]); // raw data
  726. }
  727. TRACE((WINPERF_DBG_TRACE_ERROR), (&PerflibGuid, __LINE__,
  728. PERF_QUERY_EXTDATA, ARG_TYPE_WSTR, Win32Error,
  729. pThisExtObj->szServiceName, WSTRSIZE(pThisExtObj->szServiceName),
  730. BytesLeft, sizeof(DWORD), BytesAvailable, sizeof(DWORD),
  731. NULL));
  732. // toss this buffer
  733. bBufferOK = FALSE;
  734. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  735. // <<old code>>
  736. // we'll keep the buffer, since the returned bytes left
  737. // value is ignored anyway, in order to make the
  738. // rest of this function work, we'll fix it here
  739. // BytesLeft = (DWORD)((LPBYTE)lpBufferAfter - (LPBYTE)lpBufferBefore);
  740. // << end old code >>
  741. }
  742. //
  743. // check 2: buffer after ptr should be < hi Guard page ptr
  744. //
  745. if (((LPBYTE)lpBufferAfter > (LPBYTE)lpHiGuardPage) && bBufferOK) {
  746. // see if they exceeded the allocated memory
  747. if ((LPBYTE)lpBufferAfter >= (LPBYTE)lpEndPointer) {
  748. // this is very serious since they've probably trashed
  749. // the heap by overwriting the heap sig. block
  750. // issue ERROR, buffer overrun
  751. if (THROTTLE_PERFDLL(PERFLIB_HEAP_ERROR, pThisExtObj)) {
  752. // load data for eventlog message
  753. dwDataIndex = wStringIndex = 0;
  754. dwRawDataDwords[dwDataIndex++] =
  755. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  756. szMessageArray[wStringIndex++] =
  757. pThisExtObj->szLibraryName;
  758. szMessageArray[wStringIndex++] =
  759. pThisExtObj->szServiceName;
  760. ReportEvent (hEventLog,
  761. EVENTLOG_ERROR_TYPE, // error type
  762. 0, // category (not used)
  763. (DWORD)PERFLIB_HEAP_ERROR, // event,
  764. NULL, // SID (not used),
  765. wStringIndex, // number of strings
  766. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  767. szMessageArray, // message text array
  768. (LPVOID)&dwRawDataDwords[0]); // raw data
  769. }
  770. } else {
  771. // issue ERROR, buffer overrun
  772. if (THROTTLE_PERFDLL(PERFLIB_BUFFER_OVERFLOW, pThisExtObj)) {
  773. // load data for eventlog message
  774. dwDataIndex = wStringIndex = 0;
  775. dwRawDataDwords[dwDataIndex++] =
  776. (ULONG_PTR)((LPBYTE)lpBufferAfter - (LPBYTE)lpHiGuardPage);
  777. szMessageArray[wStringIndex++] =
  778. pThisExtObj->szLibraryName;
  779. szMessageArray[wStringIndex++] =
  780. pThisExtObj->szServiceName;
  781. ReportEvent (hEventLog,
  782. EVENTLOG_ERROR_TYPE, // error type
  783. 0, // category (not used)
  784. (DWORD)PERFLIB_BUFFER_OVERFLOW, // event,
  785. NULL, // SID (not used),
  786. wStringIndex, // number of strings
  787. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  788. szMessageArray, // message text array
  789. (LPVOID)&dwRawDataDwords[0]); // raw data
  790. }
  791. }
  792. bBufferOK = FALSE;
  793. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  794. // since the DLL overran the buffer, the buffer
  795. // must be too small (no comments about the DLL
  796. // will be made here) so the status will be
  797. // changed to ERROR_MORE_DATA and the function
  798. // will return.
  799. Win32Error = ERROR_MORE_DATA;
  800. }
  801. //
  802. // check 3: check lo guard page for corruption
  803. //
  804. if (bBufferOK) {
  805. bGuardPageOK = TRUE;
  806. for (lpCheckPointer = (PUCHAR)lpLowGuardPage;
  807. lpCheckPointer < (PUCHAR)lpBufferBefore;
  808. lpCheckPointer++) {
  809. if (*lpCheckPointer != GUARD_PAGE_CHAR) {
  810. bGuardPageOK = FALSE;
  811. break;
  812. }
  813. }
  814. if (!bGuardPageOK) {
  815. // issue ERROR, Lo Guard Page corrupted
  816. if (THROTTLE_PERFDLL(PERFLIB_GUARD_PAGE_VIOLATION, pThisExtObj)) {
  817. // load data for eventlog message
  818. dwDataIndex = wStringIndex = 0;
  819. szMessageArray[wStringIndex++] =
  820. pThisExtObj->szLibraryName;
  821. szMessageArray[wStringIndex++] =
  822. pThisExtObj->szServiceName;
  823. ReportEvent (hEventLog,
  824. EVENTLOG_ERROR_TYPE, // error type
  825. 0, // category (not used)
  826. (DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event
  827. NULL, // SID (not used),
  828. wStringIndex, // number of strings
  829. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  830. szMessageArray, // message text array
  831. (LPVOID)&dwRawDataDwords[0]); // raw data
  832. }
  833. bBufferOK = FALSE;
  834. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  835. }
  836. }
  837. //
  838. // check 4: check hi guard page for corruption
  839. //
  840. if (bBufferOK) {
  841. bGuardPageOK = TRUE;
  842. for (lpCheckPointer = (PUCHAR)lpHiGuardPage;
  843. lpCheckPointer < (PUCHAR)lpEndPointer;
  844. lpCheckPointer++) {
  845. if (*lpCheckPointer != GUARD_PAGE_CHAR) {
  846. bGuardPageOK = FALSE;
  847. break;
  848. }
  849. }
  850. if (!bGuardPageOK) {
  851. // issue ERROR, Hi Guard Page corrupted
  852. if (THROTTLE_PERFDLL(PERFLIB_GUARD_PAGE_VIOLATION, pThisExtObj)) {
  853. // load data for eventlog message
  854. dwDataIndex = wStringIndex = 0;
  855. szMessageArray[wStringIndex++] =
  856. pThisExtObj->szLibraryName;
  857. szMessageArray[wStringIndex++] =
  858. pThisExtObj->szServiceName;
  859. ReportEvent (hEventLog,
  860. EVENTLOG_ERROR_TYPE, // error type
  861. 0, // category (not used)
  862. (DWORD)PERFLIB_GUARD_PAGE_VIOLATION, // event,
  863. NULL, // SID (not used),
  864. wStringIndex, // number of strings
  865. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  866. szMessageArray, // message text array
  867. (LPVOID)&dwRawDataDwords[0]); // raw data
  868. }
  869. bBufferOK = FALSE;
  870. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  871. }
  872. }
  873. //
  874. if ((lDllTestLevel <= EXT_TEST_ALL) && bBufferOK) {
  875. //
  876. // Internal consistency checks
  877. //
  878. //
  879. // Check 5: Check object length field values
  880. //
  881. // first test to see if this is a foreign
  882. // computer data block or not
  883. //
  884. pPerfData = (PERF_DATA_BLOCK *)lpBufferBefore;
  885. if ((pPerfData->Signature[0] == (WCHAR)'P') &&
  886. (pPerfData->Signature[1] == (WCHAR)'E') &&
  887. (pPerfData->Signature[2] == (WCHAR)'R') &&
  888. (pPerfData->Signature[3] == (WCHAR)'F')) {
  889. // if this is a foreign computer data block, then the
  890. // first object is after the header
  891. pObject = (PERF_OBJECT_TYPE *) (
  892. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  893. bForeignDataBuffer = TRUE;
  894. } else {
  895. // otherwise, if this is just a buffer from
  896. // an extensible counter, the object starts
  897. // at the beginning of the buffer
  898. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  899. bForeignDataBuffer = FALSE;
  900. }
  901. // go to where the pointers say the end of the
  902. // buffer is and then see if it's where it
  903. // should be
  904. dwObjectBufSize = 0;
  905. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  906. dwObjectBufSize += pObject->TotalByteLength;
  907. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  908. pObject->TotalByteLength);
  909. }
  910. if (((LPBYTE)pObject != (LPBYTE)lpCallBuffer) ||
  911. (dwObjectBufSize > BytesLeft)) {
  912. // then a length field is incorrect. This is FATAL
  913. // since it can corrupt the rest of the buffer
  914. // and render the buffer unusable.
  915. if (THROTTLE_PERFDLL(
  916. PERFLIB_INCORRECT_OBJECT_LENGTH,
  917. pThisExtObj)) {
  918. // load data for eventlog message
  919. dwDataIndex = wStringIndex = 0;
  920. dwRawDataDwords[dwDataIndex++] = NumObjectTypes;
  921. szMessageArray[wStringIndex++] =
  922. pThisExtObj->szLibraryName;
  923. szMessageArray[wStringIndex++] =
  924. pThisExtObj->szServiceName;
  925. ReportEvent (hEventLog,
  926. EVENTLOG_ERROR_TYPE, // error type
  927. 0, // category (not used)
  928. (DWORD)PERFLIB_INCORRECT_OBJECT_LENGTH, // event,
  929. NULL, // SID (not used),
  930. wStringIndex, // number of strings
  931. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  932. szMessageArray, // message text array
  933. (LPVOID)&dwRawDataDwords[0]); // raw data
  934. }
  935. bBufferOK = FALSE;
  936. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  937. }
  938. //
  939. // Test 6: Test Object definitions fields
  940. //
  941. if (bBufferOK) {
  942. // set object pointer
  943. if (bForeignDataBuffer) {
  944. pObject = (PERF_OBJECT_TYPE *) (
  945. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  946. } else {
  947. // otherwise, if this is just a buffer from
  948. // an extensible counter, the object starts
  949. // at the beginning of the buffer
  950. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  951. }
  952. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  953. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  954. pObject->DefinitionLength);
  955. if (pObject->NumCounters != 0) {
  956. pCounterDef = (PERF_COUNTER_DEFINITION *)
  957. ((LPBYTE)pObject + pObject->HeaderLength);
  958. lCtrIndex = 0;
  959. while (lCtrIndex < pObject->NumCounters) {
  960. if ((LPBYTE)pCounterDef < (LPBYTE)pNextObject) {
  961. // still ok so go to next counter
  962. pCounterDef = (PERF_COUNTER_DEFINITION *)
  963. ((LPBYTE)pCounterDef + pCounterDef->ByteLength);
  964. lCtrIndex++;
  965. } else {
  966. bBufferOK = FALSE;
  967. break;
  968. }
  969. }
  970. if ((LPBYTE)pCounterDef != (LPBYTE)pNextObject) {
  971. bBufferOK = FALSE;
  972. }
  973. }
  974. if (!bBufferOK) {
  975. break;
  976. } else {
  977. pObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  978. pObject->TotalByteLength);
  979. }
  980. }
  981. if (!bBufferOK) {
  982. if (THROTTLE_PERFDLL(
  983. PERFLIB_INVALID_DEFINITION_BLOCK,
  984. pThisExtObj)) {
  985. // load data for eventlog message
  986. dwDataIndex = wStringIndex = 0;
  987. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  988. szMessageArray[wStringIndex++] =
  989. pThisExtObj->szLibraryName;
  990. szMessageArray[wStringIndex++] =
  991. pThisExtObj->szServiceName;
  992. ReportEvent (hEventLog,
  993. EVENTLOG_ERROR_TYPE, // error type
  994. 0, // category (not used)
  995. (DWORD)PERFLIB_INVALID_DEFINITION_BLOCK, // event,
  996. NULL, // SID (not used),
  997. wStringIndex, // number of strings
  998. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  999. szMessageArray, // message text array
  1000. (LPVOID)&dwRawDataDwords[0]); // raw data
  1001. }
  1002. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  1003. }
  1004. }
  1005. //
  1006. // Test 7: Test instance field size values
  1007. //
  1008. if (bBufferOK) {
  1009. // set object pointer
  1010. if (bForeignDataBuffer) {
  1011. pObject = (PERF_OBJECT_TYPE *) (
  1012. (LPBYTE)pPerfData + pPerfData->HeaderLength);
  1013. } else {
  1014. // otherwise, if this is just a buffer from
  1015. // an extensible counter, the object starts
  1016. // at the beginning of the buffer
  1017. pObject = (PERF_OBJECT_TYPE *)lpBufferBefore;
  1018. }
  1019. for (dwIndex = 0; dwIndex < NumObjectTypes; dwIndex++) {
  1020. pNextObject = (PERF_OBJECT_TYPE *)((LPBYTE)pObject +
  1021. pObject->TotalByteLength);
  1022. if (pObject->NumInstances != PERF_NO_INSTANCES) {
  1023. pInstance = (PERF_INSTANCE_DEFINITION *)
  1024. ((LPBYTE)pObject + pObject->DefinitionLength);
  1025. lInstIndex = 0;
  1026. while (lInstIndex < pObject->NumInstances) {
  1027. PERF_COUNTER_BLOCK *pCounterBlock;
  1028. pCounterBlock = (PERF_COUNTER_BLOCK *)
  1029. ((PCHAR) pInstance + pInstance->ByteLength);
  1030. pInstance = (PERF_INSTANCE_DEFINITION *)
  1031. ((PCHAR) pCounterBlock + pCounterBlock->ByteLength);
  1032. lInstIndex++;
  1033. }
  1034. if ((LPBYTE)pInstance > (LPBYTE)pNextObject) {
  1035. bBufferOK = FALSE;
  1036. }
  1037. }
  1038. if (!bBufferOK) {
  1039. break;
  1040. } else {
  1041. pObject = pNextObject;
  1042. }
  1043. }
  1044. if (!bBufferOK) {
  1045. if (THROTTLE_PERFDLL(
  1046. PERFLIB_INCORRECT_INSTANCE_LENGTH,
  1047. pThisExtObj)) {
  1048. // load data for eventlog message
  1049. dwDataIndex = wStringIndex = 0;
  1050. dwRawDataDwords[dwDataIndex++] = pObject->ObjectNameTitleIndex;
  1051. szMessageArray[wStringIndex++] =
  1052. pThisExtObj->szLibraryName;
  1053. szMessageArray[wStringIndex++] =
  1054. pThisExtObj->szServiceName;
  1055. ReportEvent (hEventLog,
  1056. EVENTLOG_ERROR_TYPE, // error type
  1057. 0, // category (not used)
  1058. (DWORD)PERFLIB_INCORRECT_INSTANCE_LENGTH, // event,
  1059. NULL, // SID (not used),
  1060. wStringIndex, // number of strings
  1061. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  1062. szMessageArray, // message text array
  1063. (LPVOID)&dwRawDataDwords[0]); // raw data
  1064. }
  1065. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  1066. }
  1067. }
  1068. }
  1069. }
  1070. //
  1071. // if all the tests pass,then copy the data to the
  1072. // original buffer and update the pointers
  1073. if (bBufferOK) {
  1074. RtlMoveMemory (*lppDataDefinition,
  1075. lpBufferBefore,
  1076. BytesLeft); // returned buffer size
  1077. } else {
  1078. NumObjectTypes = 0; // since this buffer was tossed
  1079. BytesLeft = 0; // reset the size value since the buffer wasn't used
  1080. }
  1081. } else {
  1082. // function already copied data to caller's buffer
  1083. // so no further action is necessary
  1084. }
  1085. *lppDataDefinition = (LPVOID)((LPBYTE)(*lppDataDefinition) + BytesLeft); // update data pointer
  1086. }
  1087. } else {
  1088. if (Win32Error != ERROR_SUCCESS) {
  1089. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1090. }
  1091. if (bUnlockObjData) {
  1092. ReleaseMutex (pThisExtObj->hMutex);
  1093. }
  1094. NumObjectTypes = 0; // clear counter
  1095. }// end if function returned successfully
  1096. } except (EXCEPTION_EXECUTE_HANDLER) {
  1097. Win32Error = GetExceptionCode();
  1098. InterlockedIncrement ((LONG *)&pThisExtObj->dwErrorCount);
  1099. bException = TRUE;
  1100. if (bUnlockObjData) {
  1101. ReleaseMutex (pThisExtObj->hMutex);
  1102. bUnlockObjData = FALSE;
  1103. }
  1104. if (hPerflibFuncTimer != NULL) {
  1105. // kill timer
  1106. KillPerflibFunctionTimer (hPerflibFuncTimer);
  1107. hPerflibFuncTimer = NULL;
  1108. }
  1109. }
  1110. if (bUseSafeBuffer) {
  1111. FREEMEM (lpExtDataBuffer);
  1112. }
  1113. } else {
  1114. // unable to allocate memory so set error value
  1115. Win32Error = ERROR_OUTOFMEMORY;
  1116. } // end if temp buffer allocated successfully
  1117. //
  1118. // Update the count of the number of object types
  1119. //
  1120. ((PPERF_DATA_BLOCK) lpData)->NumObjectTypes += NumObjectTypes;
  1121. if ( Win32Error != ERROR_SUCCESS) {
  1122. if (bException ||
  1123. !((Win32Error == ERROR_MORE_DATA) ||
  1124. (Win32Error == WAIT_TIMEOUT))) {
  1125. // inform on exceptions & illegal error status only
  1126. if (THROTTLE_PERFDLL(PERFLIB_COLLECT_PROC_EXCEPTION, pThisExtObj)) {
  1127. // load data for eventlog message
  1128. dwDataIndex = wStringIndex = 0;
  1129. dwRawDataDwords[dwDataIndex++] = Win32Error;
  1130. szMessageArray[wStringIndex++] =
  1131. pThisExtObj->szServiceName;
  1132. szMessageArray[wStringIndex++] =
  1133. pThisExtObj->szLibraryName;
  1134. ReportEvent (hEventLog,
  1135. EVENTLOG_ERROR_TYPE, // error type
  1136. 0, // category (not used)
  1137. (DWORD)PERFLIB_COLLECT_PROC_EXCEPTION, // event,
  1138. NULL, // SID (not used),
  1139. wStringIndex, // number of strings
  1140. dwDataIndex*sizeof(ULONG_PTR), // sizeof raw data
  1141. szMessageArray, // message text array
  1142. (LPVOID)&dwRawDataDwords[0]); // raw data
  1143. } else {
  1144. if (bException) {
  1145. DebugPrint((0, "Extensible Counter %d generated an exception code: 0x%8.8x (%dL)\n",
  1146. NumObjectTypes, Win32Error, Win32Error));
  1147. } else {
  1148. DebugPrint((0, "Extensible Counter %d returned error code: 0x%8.8x (%dL)\n",
  1149. NumObjectTypes, Win32Error, Win32Error));
  1150. }
  1151. }
  1152. if (bException) {
  1153. DisablePerfLibrary(pThisExtObj, PERFLIB_DISABLE_ALL);
  1154. }
  1155. }
  1156. // the ext. dll is only supposed to return:
  1157. // ERROR_SUCCESS even if it encountered a problem, OR
  1158. // ERROR_MODE_DATA if the buffer was too small.
  1159. // if it's ERROR_MORE_DATA, then break and return the
  1160. // error now, since it'll just be returned again and again.
  1161. if (Win32Error == ERROR_MORE_DATA) {
  1162. lReturnValue = Win32Error;
  1163. break;
  1164. }
  1165. }
  1166. // update perf data in global section
  1167. if (pThisExtObj->pPerfSectionEntry != NULL) {
  1168. pThisExtObj->pPerfSectionEntry->llElapsedTime =
  1169. pThisExtObj->llElapsedTime;
  1170. pThisExtObj->pPerfSectionEntry->dwCollectCount =
  1171. pThisExtObj->dwCollectCount;
  1172. pThisExtObj->pPerfSectionEntry->dwOpenCount =
  1173. pThisExtObj->dwOpenCount;
  1174. pThisExtObj->pPerfSectionEntry->dwCloseCount =
  1175. pThisExtObj->dwCloseCount;
  1176. pThisExtObj->pPerfSectionEntry->dwLockoutCount =
  1177. pThisExtObj->dwLockoutCount;
  1178. pThisExtObj->pPerfSectionEntry->dwErrorCount =
  1179. pThisExtObj->dwErrorCount;
  1180. pThisExtObj->pPerfSectionEntry->dwLastBufferSize =
  1181. pThisExtObj->dwLastBufferSize;
  1182. pThisExtObj->pPerfSectionEntry->dwMaxBufferSize =
  1183. pThisExtObj->dwMaxBufferSize;
  1184. pThisExtObj->pPerfSectionEntry->dwMaxBufferRejected =
  1185. pThisExtObj->dwMaxBufferRejected;
  1186. } else {
  1187. // no data section was initialized so skip
  1188. }
  1189. } // end if this object is to be called
  1190. } // end for each object
  1191. } // else an error occurred so unable to call functions
  1192. Win32Error = DeRegisterExtObjListAccess();
  1193. } // else unable to access ext object list
  1194. HEAP_PROBE();
  1195. if (bDisabled) lReturnValue = ERROR_SERVICE_DISABLED;
  1196. return lReturnValue;
  1197. }