15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/gdi_debug_util_win.h" 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <cmath> 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <psapi.h> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <TlHelp32.h> 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/alias.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/win/scoped_handle.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void CollectChildGDIUsageAndDie(DWORD parent_pid) { 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) ; 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if(snapshot == INVALID_HANDLE_VALUE) 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int child_count = 0; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&child_count); 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int peak_gdi_count = 0; 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&peak_gdi_count); 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int sum_gdi_count = 0; 275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&sum_gdi_count); 285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int sum_user_count = 0; 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&sum_user_count); 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PROCESSENTRY32 proc_entry = {0}; 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) proc_entry.dwSize = sizeof(PROCESSENTRY32) ; 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if(!Process32First(snapshot, &proc_entry)) 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) do { 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (parent_pid != proc_entry.th32ParentProcessID) 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Got a child process. Compute GDI usage. 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::win::ScopedHandle process( 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::OpenProcess(PROCESS_QUERY_INFORMATION, 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FALSE, 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) proc_entry.th32ParentProcessID)); 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!process.IsValid()) 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int num_gdi_handles = ::GetGuiResources(process.Get(), GR_GDIOBJECTS); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int num_user_handles = ::GetGuiResources(process.Get(), GR_USEROBJECTS); 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Compute sum and peak counts. 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ++child_count; 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sum_user_count += num_user_handles; 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sum_gdi_count += num_gdi_handles; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (peak_gdi_count < num_gdi_handles) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) peak_gdi_count = num_gdi_handles; 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } while(Process32Next(snapshot, &proc_entry)); 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ::CloseHandle(snapshot) ; 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace base { 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace debug { 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void GDIBitmapAllocFailure(BITMAPINFOHEADER* header, HANDLE shared_section) { 695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Make sure parameters are saved in the minidump. 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD last_error = ::GetLastError(); 715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LONG width = header->biWidth; 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) LONG heigth = header->biHeight; 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&last_error); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&width); 775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&heigth); 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&shared_section); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int num_user_handles = GetGuiResources(GetCurrentProcess(), 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GR_USEROBJECTS); 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int num_gdi_handles = GetGuiResources(GetCurrentProcess(), 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GR_GDIOBJECTS); 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (num_gdi_handles == 0) { 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DWORD get_gui_resources_error = GetLastError(); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&get_gui_resources_error); 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&num_gdi_handles); 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&num_user_handles); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const DWORD kLotsOfHandles = 9990; 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (num_gdi_handles > kLotsOfHandles) 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) PROCESS_MEMORY_COUNTERS_EX pmc; 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) pmc.cb = sizeof(pmc); 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!GetProcessMemoryInfo(GetCurrentProcess(), 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sizeof(pmc))) { 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB 1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pmc.PagefileUsage > kLotsOfMemory) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (pmc.PrivateUsage > kLotsOfMemory) 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(false); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void* small_data = NULL; 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::debug::Alias(&small_data); 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (std::abs(heigth) * width > 100) { 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Huh, that's weird. We don't have crazy handle count, we don't have 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // ridiculous memory usage. Try to allocate a small bitmap and see if that 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // fails too. 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) header->biWidth = 5; 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) header->biHeight = -5; 1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HBITMAP small_bitmap = CreateDIBSection( 1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, reinterpret_cast<BITMAPINFO*>(&header), 1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 0, &small_data, shared_section, 0); 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Maybe the child processes are the ones leaking GDI or USER resouces. 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CollectChildGDIUsageAndDie(::GetCurrentProcessId()); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace debug 1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace base 130