示例#1
0
	bool EnableLowFragmentationHeap() {
		HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
		HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
			kernel32,
			"HeapSetInformation"));

		// On Windows 2000, the function is not exported. This is not a reason to
		// fail.
		if (!heap_set)
			return true;

		unsigned number_heaps = GetProcessHeaps(0, NULL);
		if (!number_heaps)
			return false;

		// Gives us some extra space in the array in case a thread is creating heaps
		// at the same time we're querying them.
		static const int MARGIN = 8;
		scoped_ptr<HANDLE[]> heaps(new HANDLE[number_heaps + MARGIN]);
		number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
		if (!number_heaps)
			return false;

		for (unsigned i = 0; i < number_heaps; ++i) {
			ULONG lfh_flag = 2;
			// Don't bother with the result code. It may fails on heaps that have the
			// HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
			heap_set(heaps[i],
				HeapCompatibilityInformation,
				&lfh_flag,
				sizeof(lfh_flag));
		}
		return true;
	}
示例#2
0
HIDDEN void TSTRACEValidateHeaps()
{
#ifdef DEBUG_HEAP
	if ( _heapchk() != _HEAPOK )
	{
		CkmError("*****  HEAP DAMAGE DETECTED *****");
		LOG(CallTrace, "Error: *****  HEAP DAMAGE DETECTED *****");
		DebugBreak();
	}
#endif
#ifdef DEBUG_PROCESS_HEAP
	tsByteString buffer;
	DWORD heapCount;

	buffer.resize (sizeof(HANDLE));
	heapCount = GetProcessHeaps(1, (PHANDLE)buffer.rawData());
	if ( heapCount > 1 )
	{
		buffer.resize(sizeof(HANDLE) * heapCount);
		heapCount = GetProcessHeaps(heapCount, (PHANDLE)buffer.rawData());
	}
	for (int ii = 0; ii < heapCount; ii++)
	{
		if ( !HeapValidate(((PHANDLE)buffer.rawData())[ii], 0, NULL) )
		{
			CkmError("*****  PROCESS HEAP DAMAGE DETECTED *****");
			LOG(CallTrace, "Error: *****  PROCESS HEAP DAMAGE DETECTED *****");
			//            DebugBreak();
		}
	}
#endif // DEBUG_PROCESS_HEAP
}
示例#3
0
//-------------------------------------------------------------------//
// CompactHeap()																		//
//-------------------------------------------------------------------//
// This function compacts the application's heap(s) and returns
// the maximum block size available after compaction.
//
// Not sure which of the heaps we encounter is the "default" used by
// the program.  We compact them all.
//
// If you want a heap count, provide the address of the integer
// to set.
//
// NOTE: we only allow 25 heaps max here.
//-------------------------------------------------------------------//
unsigned int CompactHeap( int* pnHeapCount )
{
	// This does ALL heaps.
	unsigned int unLargestBlock = 0;
	HANDLE hHeaps[25];
	DWORD dwHeaps = GetProcessHeaps( 25, hHeaps );
	ASSERT( dwHeaps < 25 );
	if ( dwHeaps < 25 )
	{
		for ( int nA = 0; nA < dwHeaps; nA++ )
		{
			unLargestBlock = max( unLargestBlock, HeapCompact( hHeaps[nA], 0 ) );
		}
	}

	if ( pnHeapCount != 0 )
		*pnHeapCount = dwHeaps;

	return unLargestBlock;

	/*
	// This does the default heap (the CRT heap? not according to 
	// M$DN support...).
	return HeapCompact( GetProcessHeap(), 0 );
	*/
}
示例#4
0
BOOL My_GetProcessHeaps()
{
	DWORD NumberOfHeaps=NULL;
	PHANDLE ProcessHeaps=NULL;
	DWORD returnVal_Real = NULL;
	DWORD returnVal_Intercepted = NULL;

	DWORD error_Real = 0;
	DWORD error_Intercepted = 0;
	__try{
	disableInterception();
	returnVal_Real = GetProcessHeaps (NumberOfHeaps,ProcessHeaps);
	error_Real = GetLastError();
	enableInterception();
	returnVal_Intercepted = GetProcessHeaps (NumberOfHeaps,ProcessHeaps);
	error_Intercepted = GetLastError();
	}__except(puts("in filter"), 1){puts("exception caught");}
	return ((returnVal_Real == returnVal_Intercepted) && (error_Real == error_Intercepted));
}
示例#5
0
文件: debug.cpp 项目: mingpen/OpenNT
void CHECKHEAP()
// Validate all the heaps in this process
	{
	HANDLE rgHeap[100];
	DWORD cHeap = GetProcessHeaps(100, rgHeap);
	ASSERT(cHeap > 0 && cHeap <= 100);
	for (ULONG iHeap=0; iHeap<cHeap; iHeap++)
		{
		ASSERT(HeapValidate(rgHeap[iHeap],0,NULL));
		}
	}
示例#6
0
文件: ff13.cpp 项目: Gentle/gedosato
void FF13Plugin::initialize(unsigned rw, unsigned rh, D3DFORMAT bbformat, D3DFORMAT dssformat) {
	GenericPlugin::initialize(rw, rh, bbformat, dssformat);

	// Force low fragmentation heap
	HANDLE heaps[128];
	DWORD numHeaps = GetProcessHeaps(128, heaps);
	for(DWORD i = 0; i < numHeaps; ++i) {
		ULONG HeapInformation = HEAP_LFH;
		BOOL res = HeapSetInformation(heaps[i],	HeapCompatibilityInformation, &HeapInformation, sizeof(HeapInformation));
		if(res != FALSE) {
			SDLOG(1, "Low-fragmentation heap enabled for heap #%d.\n", i);
		} else {
			SDLOG(1, "Failed to enable low-fragmentation for heap #%d; LastError %d.\n", i, GetLastError());
		}
	}
}
示例#7
0
void forceLFHs() {
	// Force low fragmentation heap
	SDLOG(2, "Starting heap adjustment (LFH)\n");
	HANDLE heaps[256];
	DWORD numHeaps = GetProcessHeaps(256, heaps);
	for(DWORD i = 0; i < numHeaps; ++i) {
		ULONG HeapInformation = HEAP_LFH;
		BOOL res = HeapSetInformation(heaps[i], HeapCompatibilityInformation, &HeapInformation, sizeof(HeapInformation));
		if(res != FALSE) {
			SDLOG(1, "Low-fragmentation heap enabled for heap #%d.\n", i);
		}
		else {
			SDLOG(1, "Failed to enable low-fragmentation for heap #%d; LastError %d.\n", i, GetLastError());
		}
	}
	SDLOG(2, "Completed heap adjustment (LFH)\n");
}
示例#8
0
void print_rusage (void)
{
#if defined(WIN32)
//int i;
  static SIZE_T previous = 0;
  DWORD minWSS, maxWSS;
  GetProcessWorkingSetSize (GetCurrentProcess(), &minWSS, &maxWSS);

#if 0
  const DWORD maxH = 100;
  HANDLE heaps[maxH], nbrh;
  nbrh = GetProcessHeaps (maxH, heaps);
  if (nbrh > maxH) nbrh = maxH;
  unsigned long hsize = 0;
  for (i = 0; i < nbrh; ++i)
    hsize += HeapSize (heaps[i], 0, heaps[i]);

  MEMORY_BASIC_INFORMATION mbi;
  mbi.RegionSize = 1234;
  if (VirtualQuery (NULL, &mbi, sizeof(mbi)) != sizeof(mbi))
  {
  }

  printf ("RUSAGE: VQ=%ld minWSS=%ld maxWSS=%ld\n", mbi.RegionSize, minWSS, maxWSS);
#endif

  PROCESS_MEMORY_COUNTERS PMC;
  memset(&PMC, 0, sizeof(PMC));

  // Set size of structure
  PMC.cb = sizeof(PMC);

  // Get memory usage
  GetProcessMemoryInfo(GetCurrentProcess(), &PMC, sizeof(PMC));

  printf ("RUSAGE: PFU += %6ld kb      peakPFU=%3ld.%03ld  peakWSS=%3ld.%03ld (Mbytes)\n",
         (PMC.PeakPagefileUsage-previous)/1024,
         PMC.PeakPagefileUsage/(1024*1024), (PMC.PeakPagefileUsage%(1024*1024))/1000,
         PMC.PeakWorkingSetSize/(1024*1024), (PMC.PeakWorkingSetSize%(1024*1024))/1000);

  previous = PMC.PeakPagefileUsage;

#endif
}
示例#9
0
void KMemDump::Dump(unsigned char * start, unsigned offset, int size, int unitsize)
{
    if ( offset==0 )
    {
	    HANDLE hHeaps[10];
	    int no = GetProcessHeaps(10, hHeaps);
	
        // walk the heap if it is a heap
	    for (int i=0; i<no; i++)
		    if ( start == hHeaps[i] )
		    {
			    PROCESS_HEAP_ENTRY entry;

			    entry.lpData = NULL;

			    while ( HeapWalk(start, & entry) )
			    {
				    wsprintf(m_line, "%x %d+%d bytes %x\r\n", 
                        entry.lpData, entry.cbData,
                        entry.cbOverhead, entry.iRegionIndex);
				
                    * m_stream << m_line;
			    }
			    * m_stream << "\r\n";
			
			    break;
		    }			
    }

	* m_stream << size;
	* m_stream << " bytes\n";
	while (size>0)
	{
		DumpLine(start, offset, unitsize);
		start += 16;
		size  -= 16;

		* m_stream << m_line;
	}
}
int APIENTRY WINMAIN(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	const S32 MAX_HEAPS = 255;
	DWORD heap_enable_lfh_error[MAX_HEAPS];
	S32 num_heaps = 0;
	
#if WINDOWS_CRT_MEM_CHECKS && !INCLUDE_VLD
	_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); // dump memory leaks on exit
#elif 1
	// Experimental - enable the low fragmentation heap
	// This results in a 2-3x improvement in opening a new Inventory window (which uses a large numebr of allocations)
	// Note: This won't work when running from the debugger unless the _NO_DEBUG_HEAP environment variable is set to 1

	_CrtSetDbgFlag(0); // default, just making explicit
	
	ULONG ulEnableLFH = 2;
	HANDLE* hHeaps = new HANDLE[MAX_HEAPS];
	num_heaps = GetProcessHeaps(MAX_HEAPS, hHeaps);
	for(S32 i = 0; i < num_heaps; i++)
	{
		bool success = HeapSetInformation(hHeaps[i], HeapCompatibilityInformation, &ulEnableLFH, sizeof(ulEnableLFH));
		if (success)
			heap_enable_lfh_error[i] = 0;
		else
			heap_enable_lfh_error[i] = GetLastError();
	}
#endif
	
	// *FIX: global
	gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);

	LLAppViewerWin32* viewer_app_ptr = new LLAppViewerWin32(lpCmdLine);
	
	viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);

	// Set a debug info flag to indicate if multiple instances are running.
	bool found_other_instance = !create_app_mutex();
	gDebugInfo["FoundOtherInstanceAtStartup"] = LLSD::Boolean(found_other_instance);

	bool ok = viewer_app_ptr->init();
	if(!ok)
	{
		llwarns << "Application init failed." << llendl;
		return -1;
	}
	
	// Have to wait until after logging is initialized to display LFH info
	if (num_heaps > 0)
	{
		llinfos << "Attempted to enable LFH for " << num_heaps << " heaps." << llendl;
		for(S32 i = 0; i < num_heaps; i++)
		{
			if (heap_enable_lfh_error[i])
			{
				llinfos << "  Failed to enable LFH for heap: " << i << " Error: " << heap_enable_lfh_error[i] << llendl;
			}
		}
	}
	
	// Run the application main loop
	if(!LLApp::isQuitting()) 
	{
		viewer_app_ptr->mainLoop();
	}

	if (!LLApp::isError())
	{
		//
		// We don't want to do cleanup here if the error handler got called -
		// the assumption is that the error handler is responsible for doing
		// app cleanup if there was a problem.
		//
#if WINDOWS_CRT_MEM_CHECKS
    llinfos << "CRT Checking memory:" << llendflush;
	if (!_CrtCheckMemory())
	{
		llwarns << "_CrtCheckMemory() failed at prior to cleanup!" << llendflush;
	}
	else
	{
		llinfos << " No corruption detected." << llendflush;
	}
#endif
	
	gGLActive = TRUE;

	viewer_app_ptr->cleanup();
	
#if WINDOWS_CRT_MEM_CHECKS
    llinfos << "CRT Checking memory:" << llendflush;
	if (!_CrtCheckMemory())
	{
		llwarns << "_CrtCheckMemory() failed after cleanup!" << llendflush;
	}
	else
	{
		llinfos << " No corruption detected." << llendflush;
	}
#endif
	 
	}
	delete viewer_app_ptr;
	viewer_app_ptr = NULL;

	//start updater
	if(LLAppViewer::sUpdaterInfo)
	{
		_spawnl(_P_NOWAIT, LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), LLAppViewer::sUpdaterInfo->mParams.str().c_str(), NULL);

		delete LLAppViewer::sUpdaterInfo ;
		LLAppViewer::sUpdaterInfo = NULL ;
	}

	return 0;
}
示例#11
0
void KSnapShot::Shot(KListView * list)
{
    unsigned char * start = NULL;
    MEMORY_BASIC_INFORMATION info;

	KPEFile  module;
	void   * lastmodule = NULL;
	
	typedef enum { nMaxHeaps = 10 };
	HANDLE   ProcHeaps[nMaxHeaps];

	int heaps = GetProcessHeaps(nMaxHeaps, ProcHeaps);

    while ( VirtualQuery(start, & info, sizeof(info)) )
    {
		KRegion * pRegion = NULL;

		// compute CRC for committed region
	    if (info.State == MEM_COMMIT)
		{
			pRegion = FindRegion(start, info.RegionSize);		
            if (pRegion)
            {
        		pRegion->type    = info.Type;
				pRegion->lastcrc = pRegion->crc;
                pRegion->crc     = m_crc.Update(0, start, info.RegionSize);
				pRegion->count ++;
            }
		}
		
		if (list)
		{
			TCHAR temp[MAX_PATH];
			const TCHAR * p ;

			if ( pRegion && pRegion->count>=2 )
			{
				wsprintf(temp, "%04x", pRegion->lastcrc);
				list->AddItem(0, temp, ( pRegion->lastcrc != pRegion->crc ) + 1);
			}
			else
				list->AddItem(0, "     ", 0);

			if ( pRegion )
			{
				wsprintf(temp, "%04x", pRegion->crc);
				list->AddItem(1, temp);
			}
			
			wsprintf(temp, "%08lx", info.BaseAddress);	list->AddItem(2, temp);
			wsprintf(temp, "%08lx", info.RegionSize);   list->AddItem(3, temp);

			switch (info.State)
			{
				case MEM_FREE:    p = "F "; break;
				case MEM_RESERVE: p = "R "; break;
				case MEM_COMMIT:  p = "C "; break;
				default:          p = "? ";   
			}
			strcpy(temp, p);

			if ( info.State != MEM_FREE)
			{
				switch (info.Type)
				{
					case MEM_IMAGE:   p = "I "; break;
					case MEM_MAPPED:  p = "M "; break;
					case MEM_PRIVATE: p = "P "; break;
					default:          p = "? ";
				}
				strcat(temp, p);

				AddFlags(temp, info.AllocationProtect, Protections, sizeof(Protections)/sizeof(Protections[0]));
			}
			list->AddItem(4, temp);

/*
			char t[MAX_PATH];
			wsprintf(t, "%8lx ", info.AllocationBase);
			strcat(temp, t);

			if (info.State != MEM_RESERVE)
				AddFlags(temp, info.Protect, Protections, sizeof(Protections)/sizeof(Protections[0]));
*/

			if (info.State != MEM_FREE )
				if ( GetModuleFileName((HINSTANCE) info.BaseAddress, temp, sizeof(temp)) )
				{
					if (lastmodule)
					{
						module.Unload();
						lastmodule = NULL;
					}
				
					if ( module.Load(temp) )
						lastmodule = info.BaseAddress;

					// remove the directory path, keep only the filename
					if ( strchr(temp, '\\') )
					{
						for (char *p = strchr(temp, '\\') + 1;
									   strchr(p, '\\');
								   p = strchr(p, '\\') + 1);
						list->AddItem(5, p);
					}
					else 
						list->AddItem(5, temp);
				}
				else
				{
					const char * p = NULL;

					if (lastmodule != NULL)
						p = module.GetSectionName((unsigned) info.BaseAddress - (unsigned) lastmodule);

					if (p == NULL)
						for (int h=0; h<heaps; h++)
							if ( info.BaseAddress == ProcHeaps[h] )
							{
								wsprintf(temp, "Heap %d", h+1);
								p = temp;
								break;
							}

					if (p == NULL)
						if ( ( (unsigned) (& p) >= (unsigned) info.BaseAddress ) &&
						     ( (unsigned) (& p) <  (unsigned) info.BaseAddress + info.RegionSize ) )
							p = "Stack";

					if ( p )
						list->AddItem(5, p);
				}
							
		}

        start += info.RegionSize;

        if (start == 0)
            break;
    }

	if (lastmodule)
		module.Unload();
}
示例#12
0
void SaveHeapLog()
{
  FILE *f;
  _HEAPINFO hi;
  char block[129],*ad;
  block[128]=0;
  int code;
  HANDLE heaps[200];
  DWORD n;
  PROCESS_HEAP_ENTRY phe;

  f=fopen(WriteDir+SLASH+"heap.log","wb");

  SetLastError(0);
  n=GetProcessHeaps(200,heaps);
  heaps[n]=GetProcessHeap();n++;
  fprintf(f,"There are %i heaps for Steem\r\n",n);
  for (DWORD i=0;i<n;i++){
    code=HeapValidate(heaps[i],0,NULL);
    if (code){
      fprintf(f,"Heap %u okay\r\n",i);
    }else{
      fprintf(f,"Heap %u has an error in it!\r\n",i);
    }
    HeapLock(heaps[i]);
    phe.lpData=NULL;
    while (HeapWalk(heaps[i],&phe)){
      fprintf(f,"%s%X\r\n","Bad node, address=",(unsigned long)(phe.lpData));
      ad=((char*)phe.lpData)-64;
      for (int n=0;n<128;n++){
        block[n]=*(ad++);
        if (block[n]==0) block[n]='\\';
        if (block[n]==10) block[n]='\\';
        if (block[n]==13) block[n]='\\';
      }
      fprintf(f,"%s\r\n",block);
    }
    HeapUnlock(heaps[i]);
    if (phe.lpData==NULL) DisplayLastError();
  }

  fprintf(f,"\r\n\r\n");
  code=_heapchk();
  if (code==_HEAPOK){
    fprintf(f,"%s\r\n","Heap okay, walking:");
  }else if (code==_HEAPBADNODE){
    fprintf(f,"%s\r\n","Heap has bad node! Walking anyway:");
  }
  hi._pentry=NULL;
  for(;;){
    code=_rtl_heapwalk(&hi);
    if (code==_HEAPEND) break;
    if (code==_HEAPBADNODE){
      fprintf(f,"%s%X\r\n","Bad node, address=",(unsigned long)(hi.__pentry));
      ad=((char*)hi._pentry)-64;
      for (int n=0;n<128;n++){
        block[n]=*(ad++);
        if (block[n]==0) block[n]='\\';
        if (block[n]==10) block[n]='\\';
        if (block[n]==13) block[n]='\\';
      }
      fprintf(f,"%s\r\n",block);
    }else if (code==_HEAPOK){
      fprintf(f,"%s%X\r\n","Good node, address=",(unsigned long)(hi.__pentry));
    }
  }
  fclose(f);
}
示例#13
0
void CCompInfo::GetHeaps()
{
		memset(m_aHeaps,0,sizeof(m_aHeaps));
		m_nHeaps = GetProcessHeaps(sizeof(m_aHeaps)/sizeof(m_aHeaps[0]),m_aHeaps);
};
示例#14
0
DWORD prim_getProcessHeaps(DWORD arg1,void * arg2)
{ DWORD res1;
  do {res1 = GetProcessHeaps(arg1, arg2);
      
      return((DWORD)(res1));} while(0);
}
示例#15
0
文件: heapwalk.c 项目: mingpen/OpenNT
int
_cdecl
main()
{
    struct _heapinfo info;
    PROCESS_HEAP_ENTRY Entry;
    size_t i;
    LPBYTE s;

    info._pentry = NULL;
    setvbuf( stdout, MyBuffer, _IOFBF, sizeof( MyBuffer ) );
    _heapset( 0xAE );
    while (_heapwalk( &info ) == _HEAPOK) {
        printf( "%08x: %05x - %s", info._pentry, info._size, info._useflag ? "busy" : "free" );
        if (info._useflag == _FREEENTRY) {
            s = (LPBYTE)info._pentry;
            for (i=0; i<info._size; i++) {
                if (s[i] != 0xAE) {
                    printf( " *** free block invalid at offset %x [%x]", i, s[i] );
                    break;
                    }
                }
            }

        printf( "\n" );
        fflush( stdout );
        }
    printf( "*** end of heap ***\n\n" );
    fflush( stdout );

    NumberOfHeaps = GetProcessHeaps( 64, ProcessHeaps );
    Entry.lpData = NULL;
    for (i=0; i<NumberOfHeaps; i++) {
        printf( "Heap[ %u ]: %x  HeapCompact result: %lx\n",
                i,
                ProcessHeaps[ i ],
                HeapCompact( ProcessHeaps[ i ], 0 )
              );
        while (HeapWalk( ProcessHeaps[ i ], &Entry )) {
            if (Entry.wFlags & PROCESS_HEAP_REGION) {
                printf( "    %08x: %08x - Region(First: %08x  Last: %08x  Committed: %x  Uncommitted: %08x)\n",
                        Entry.lpData, Entry.cbData,
                        Entry.Region.lpFirstBlock,
                        Entry.Region.lpLastBlock,
                        Entry.Region.dwCommittedSize,
                        Entry.Region.dwUnCommittedSize
                      );
                }
            else
            if (Entry.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) {
                printf( "    %08x: %08x - Uncommitted\n",
                        Entry.lpData, Entry.cbData
                      );
                }
            else
            if (Entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) {
                printf( "    %08x: %08x - Busy", Entry.lpData, Entry.cbData );
                if (Entry.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) {
                    printf( "  hMem: %08x", Entry.Block.hMem );
                    }

                if (Entry.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) {
                    printf( "  DDE" );
                    }

                printf( "\n" );
                }
            else {
                printf( "    %08x: %08x - Free\n", Entry.lpData, Entry.cbData );
                }

            fflush( stdout );
            }

        printf( "*** end of heap ***\n\n" );
        fflush( stdout );
        }

    return 0;
}
示例#16
0
MX_EXPORT int
mx_heap_check( unsigned long heap_flags )
{
	static const char fname[] = "mx_heap_check()";

	DWORD number_of_heaps;
	DWORD maximum_number_of_heaps;
	HANDLE heap_handle_array[100];
	HANDLE heap_handle;
	BOOL validate_status;
	int heap_ok;
	unsigned long i;

	/* This implementation does not call GetProcessHeaps() in a loop
	 * to resize heap_handle_array to the right size, since this will
	 * result in an infinite loop if mx_heap_check() is called from
	 * within any of the mx_win32_... allocation functions.  So we
	 * use a fixed array instead which is probably large enough.
	 */

	static const char getprocessheaps_error[] =
		"ERROR: A call to GetProcessHeaps() failed.\n";

	static const char toomanyheaps_error[] = 
		"ERROR: Too many heaps reported by GetProcessHeaps().  "
		"Increase the size of heap_handle_array and recompile MX "
		"to fix this.\n";

	maximum_number_of_heaps = sizeof( heap_handle_array )
					/ sizeof( heap_handle_array[0] );

	number_of_heaps = GetProcessHeaps( maximum_number_of_heaps,
						heap_handle_array );

	if ( number_of_heaps == 0 ) {
		write(2, getprocessheaps_error, sizeof(getprocessheaps_error));
	}

	if ( number_of_heaps > maximum_number_of_heaps ) {
		write(2, toomanyheaps_error, sizeof(toomanyheaps_error));
		return FALSE;
	}

	heap_ok = TRUE;

	for ( i = 0; i < number_of_heaps; i++ ) {

		heap_handle = heap_handle_array[i];

		validate_status = HeapValidate( heap_handle, 0, 0 );

		if ( validate_status == 0 ) {
			if ( heap_flags & MXF_HEAP_CHECK_CORRUPTED_VERBOSE ) {
#if defined(_WIN64)
			    mx_warning( "%s: Heap %lu (%#I64x) is CORRUPTED.",
					fname, i, (uint64_t) heap_handle );
#else
			    mx_warning( "%s: Heap %lu (%#lx) is CORRUPTED.",
					fname, i, (unsigned long) heap_handle );
#endif
			}

			heap_ok = FALSE;
		} else {
			if ( heap_flags & MXF_HEAP_CHECK_OK_VERBOSE ) {
#if defined(_WIN64)
			    mx_info( "%s: Heap %lu (%#I64x) is OK.",
					fname, i, (uint64_t) heap_handle );
#else
			    mx_info( "%s: Heap %lu (%#lx) is OK.",
					fname, i, (unsigned long) heap_handle );
#endif
			}
		}
	}

	if ( heap_ok ) {
		if ( heap_flags & MXF_HEAP_CHECK_OK ) {
			mx_info( "%s: Heap is OK", fname );
		}
	} else {
		if ( heap_flags & MXF_HEAP_CHECK_CORRUPTED ) {
			mx_warning("%s: Heap is corrupted.", fname);
		}
	}

	if ( heap_flags & MXF_HEAP_CHECK_STACK_TRACEBACK ) {
		mx_stack_traceback();
	}

	return heap_ok;
}