DynamoRIO / DynamoRIO/drmemory

GDI false positives from system DC used in more than one thread

Open
#1,192 1 comment 0 reactions 0 assignees View on GitHub
Bug-FalsePositive Migrated OpSys-Windows Priority-Medium
Dominant language
C
Stars
2.7k
Forks
290
PR merge metrics
No merged PRs in 30d

Description

_From [bruen...@google.com](https://code.google.com/u/109494838902877177630/) on April 24, 2013 16:46:18_

xref http://crbug.com/234484 Error `#1`: GDI USAGE ERROR: DC created by one thread 11236 and used by another 6900
#0 USER32.dll!BitmapFromDIB
#1 USER32.dll!ConvertDIBBitmap
#2 USER32.dll!CopyBmp
#3 USER32.dll!CreateIconIndirect
#4 ui.dll!IconUtil::CreateHICONFromSkBitmap [e:\derek\chromium\src\ui\gfx\icon_util.cc:120]
#5 chrome::`anonymous namespace'::SetOverlayIcon [e:\derek\chromium\src\chrome\browser\ui\views\frame\taskbar_decorator_win.cc:65]
\# 6 base::internal::RunnableAdapter >)>::Run [e:\derek\chromium\src\base\bind_internal.h:228]
\# 7 base::internal::InvokeHelper<0,void,base::internal::RunnableAdapter >)>,void __cdecl(HWND__ * const &,scoped_ptr >)>::MakeItSo [e:\derek\chromium\src\base\bind_internal.h:899]
\# 8 base::internal::Invoker<2,base::internal::BindState >)>,void __cdecl(HWND__ *,scoped_ptr >),void __cdecl(HW [e:\derek\chromium\src\base\bind_internal.h:1257]
\# 9 base.dll!base::Callback::Run [e:\derek\chromium\src\base\callback.h:396]
\#10 base.dll!base::`anonymous namespace'::WorkItemCallback [e:\derek\chromium\src\base\threading\worker_pool_win.cc:32]
#11 ntdll.dll!RtlpTpWorkCallback
Note: @0:00:29.820 in thread 6900
Note: DC was allocated here:
Note: # 0 system call NtGdiGetDCforBitmap
Note: # 1 GDI32.dll!SetDIBits
Note: # 2 USER32.dll!BitmapFromDIB
Note: # 3 USER32.dll!ConvertDIBBitmap
Note: # 4 USER32.dll!ConvertDIBIcon
Note: # 5 USER32.dll!ObjectFromDIBResource
Note: # 6 USER32.dll!LoadIcoCur
Note: # 7 USER32.dll!LoadIconW
Note: # 8 GetAppIcon [e:\derek\chromium\src\chrome\browser\app_icon_win.cc:33]
Note: # 9 ChromeViewsDelegate::GetDefaultWindowIcon [e:\derek\chromium\src\chrome\browser\ui\views\chrome_views_delegate.cc:134]
Note: `#10` views.dll!views::HWNDMessageHandler::GetDefaultWindowIcon [e:\derek\chromium\src\ui\views\win\hwnd_message_handler.cc:845]
Note: `#11` ui.dll!ui::WindowImpl::GetWindowClassAtom [e:\derek\chromium\src\ui\base\win\window_impl.cc:264]

USER32!BitmapFromDIB+0x1ce:
76b5e1f6 57 push edi
76b5e1f7 56 push esi
76b5e1f8 ff7524 push dword ptr [ebp+0x24]
76b5e1fb 8b450c mov eax,[ebp+0xc]
76b5e1fe 99 cdq
76b5e1ff 33c2 xor eax,edx
76b5e201 2bc2 sub eax,edx
76b5e203 50 push eax
76b5e204 57 push edi
76b5e205 ff75e4 push dword ptr [ebp-0x1c]
76b5e208 ff350001bc76 push dword ptr [USER32!ghdcBits2 (76bc0100)]
76b5e20e ff157002b576 call dword ptr [USER32!_imp__SetDIBits (76b50270)]
int SetDIBits(
_In_ HDC hdc,

USER32!BitmapFromDIB+0xa5:
76b5e149 6a00 push 0x0
76b5e14b 56 push esi
76b5e14c 6a00 push 0x0
76b5e14e 6a02 push 0x2
76b5e150 56 push esi
76b5e151 ff350001bc76 push dword ptr [USER32!ghdcBits2 (76bc0100)]
76b5e157 ff157802b576 call dword ptr [USER32!_imp__CreateDIBitmap (76b50278)]

HBITMAP CreateDIBitmap(
_In_ HDC hdc,

xref this comment in gdicheck.c:
/\* w/o early injection we end up not seeing creation of DC's like
\* USER32!ghdcBits2
*/

GDI32!SetDIBits+0x4f:
758b75df ff750c push dword ptr [ebp+0xc]
758b75e2 e889ffffff call GDI32!NtGdiGetDCforBitmap (758b7570)
758b75e7 8bf8 mov edi,eax
758b75e9 3bfb cmp edi,ebx
758b75eb 0f84324b0000 je GDI32!SetDIBits+0x5d (758bc123)

GDI32!SetDIBits+0x5d:
758bc123 ff7508 push dword ptr [ebp+0x8]
758bc126 e8c993ffff call GDI32!CreateCompatibleDC (758b54f4)
758bc12b 8bf8 mov edi,eax
758bc12d c745fc01000000 mov dword ptr [ebp-0x4],0x1
758bc134 3bfb cmp edi,ebx
758bc136 0f85c3b4ffff jne GDI32!SetDIBits+0x7e (758b75ff)

GDI32!SetDIBits+0x74:
758b75f1 57 push edi
758b75f2 e80ef8ffff call GDI32!SaveDC (758b6e05)
758b75f7 85c0 test eax,eax
758b75f9 0f844a4b0000 je GDI32!SetDIBits+0x46 (758bc149)

Theory: NtGdiGetDCforBitmap is returning pre-existing DC USER32!ghdcBits2
0:004> dv
hdc = 0xbd010c55
0:004> dd user32!ghdcBits2
76bc0100 bd010c55 00000000 05e00040 05dd0000

yup!

And user32!ghdcBits2 violates rules about use in multiple threads, it seems.

so does NtGdiGetDCforBitmap ever "create" a bitmap? is it like a Get and
needs a Release?

in ReactOS, it just returns the HDC: it does none of the work that UserGetDC does.

action items:
1) ignore NtGdiGetDCforBitmap?
or keep considering an "alloc" b/c we want that DC in our table?
just don't complain if it's not released. we should see a real release
later so shouldn't end up stale in table. but, we should mark
as a non-real-alloc, b/c any de-alloc need not be in the thread
that called NtGdiGetDCforBitmap.

2) presumably user32!ghdcBits2 is created by initial thread during user32
startup? and freed at exit? so seems ok to use a DC in different
threads, just not simultaneously? is SaveDC relevant here?

initialized here:
USER32!ClientThreadSetup+0x117:
76b5cdd5 ff159c02b576 call dword ptr [USER32!_imp__CreateCompatibleDC (76b5029c)]
76b5cddb a30001bc76 mov [USER32!ghdcBits2 (76bc0100)],eax
0:000> kn
# ChildEBP RetAddr
00 0045f018 76b59d82 USER32!ClientThreadSetup+0x122
01 0045f01c 7717010a USER32!__ClientThreadSetup+0x5
02 0045f034 758b6388 ntdll!KiUserCallbackDispatcher+0x2e
03 76b59d82 ffffff25 GDI32!GdiDllInitialize+0x1c

**\* TODO can we find ghdcBits2 w/o syms?

I can't find it in any exported routine: only deep inside user32.

may need to turn this GDI warning off by default.

_Original issue: http://code.google.com/p/drmemory/issues/detail?id=1192_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.