1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "base/debug/gdi_debug_util_win.h"
11 #include "base/debug/alias.h"
12 #include "base/logging.h"
13 #include "base/win/scoped_handle.h"
17 void CollectChildGDIUsageAndDie(DWORD parent_pid
) {
18 HANDLE snapshot
= CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS
, 0) ;
19 if(snapshot
== INVALID_HANDLE_VALUE
)
23 base::debug::Alias(&child_count
);
24 int peak_gdi_count
= 0;
25 base::debug::Alias(&peak_gdi_count
);
26 int sum_gdi_count
= 0;
27 base::debug::Alias(&sum_gdi_count
);
28 int sum_user_count
= 0;
29 base::debug::Alias(&sum_user_count
);
31 PROCESSENTRY32 proc_entry
= {0};
32 proc_entry
.dwSize
= sizeof(PROCESSENTRY32
) ;
33 if(!Process32First(snapshot
, &proc_entry
))
37 if (parent_pid
!= proc_entry
.th32ParentProcessID
)
39 // Got a child process. Compute GDI usage.
40 base::win::ScopedHandle
process(
41 ::OpenProcess(PROCESS_QUERY_INFORMATION
,
43 proc_entry
.th32ParentProcessID
));
47 int num_gdi_handles
= ::GetGuiResources(process
.Get(), GR_GDIOBJECTS
);
48 int num_user_handles
= ::GetGuiResources(process
.Get(), GR_USEROBJECTS
);
50 // Compute sum and peak counts.
52 sum_user_count
+= num_user_handles
;
53 sum_gdi_count
+= num_gdi_handles
;
54 if (peak_gdi_count
< num_gdi_handles
)
55 peak_gdi_count
= num_gdi_handles
;
57 } while(Process32Next(snapshot
, &proc_entry
));
59 ::CloseHandle(snapshot
) ;
68 void GDIBitmapAllocFailure(BITMAPINFOHEADER
* header
, HANDLE shared_section
) {
69 // Make sure parameters are saved in the minidump.
70 DWORD last_error
= ::GetLastError();
72 LONG width
= header
->biWidth
;
73 LONG heigth
= header
->biHeight
;
75 base::debug::Alias(&last_error
);
76 base::debug::Alias(&width
);
77 base::debug::Alias(&heigth
);
78 base::debug::Alias(&shared_section
);
80 int num_user_handles
= GetGuiResources(GetCurrentProcess(),
83 int num_gdi_handles
= GetGuiResources(GetCurrentProcess(),
85 if (num_gdi_handles
== 0) {
86 DWORD get_gui_resources_error
= GetLastError();
87 base::debug::Alias(&get_gui_resources_error
);
91 base::debug::Alias(&num_gdi_handles
);
92 base::debug::Alias(&num_user_handles
);
94 const DWORD kLotsOfHandles
= 9990;
95 if (num_gdi_handles
> kLotsOfHandles
)
98 PROCESS_MEMORY_COUNTERS_EX pmc
;
100 if (!GetProcessMemoryInfo(GetCurrentProcess(),
101 reinterpret_cast<PROCESS_MEMORY_COUNTERS
*>(&pmc
),
105 const size_t kLotsOfMemory
= 1500 * 1024 * 1024; // 1.5GB
106 if (pmc
.PagefileUsage
> kLotsOfMemory
)
108 if (pmc
.PrivateUsage
> kLotsOfMemory
)
111 void* small_data
= NULL
;
112 base::debug::Alias(&small_data
);
114 if (std::abs(heigth
) * width
> 100) {
115 // Huh, that's weird. We don't have crazy handle count, we don't have
116 // ridiculous memory usage. Try to allocate a small bitmap and see if that
119 header
->biHeight
= -5;
120 HBITMAP small_bitmap
= CreateDIBSection(
121 NULL
, reinterpret_cast<BITMAPINFO
*>(&header
),
122 0, &small_data
, shared_section
, 0);
124 // Maybe the child processes are the ones leaking GDI or USER resouces.
125 CollectChildGDIUsageAndDie(::GetCurrentProcessId());