blob: f264ce478ce1ea33a4be59d588a00a59d1acff35 [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2012 Google, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Tests GDI checks from i#752 */
#ifndef WINDOWS
# error Windows-only
#endif
#include <windows.h>
#include <process.h> /* for _beginthreadex */
#include <assert.h>
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")
static void
test_DC_free(void)
{
// Test DrMem check for: proper pairing GetDC|ReleaseDC and CreateDC|DeleteDC
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
// Not checking all the {Select,Delete,Release}* calls since some are
// deliberately erroneous and meant to fail. Note that on some platforms
// at least the GDI impl is robust and handles some of these errors DrMem
// is detecting.
DeleteDC(mydc); // error raised
mydc = GetDC(NULL);
assert(mydc != NULL);
HDC dupdc = CreateCompatibleDC(mydc);
assert(dupdc != NULL);
ReleaseDC(NULL, dupdc); // error raised
}
static unsigned int WINAPI
thread_dup_DC(void *arg)
{
HDC *dc_out = (HDC *) arg;
// ok for *dc_out to be NULL
HDC dupdc = CreateCompatibleDC(*dc_out);
assert(dupdc != NULL);
*dc_out = dupdc;
return 0;
}
static unsigned int WINAPI
thread_select(void *arg)
{
HDC mydc = (HDC) arg;
assert(mydc != NULL);
HBITMAP mybm = CreateBitmap(30, 30, 1, 16, NULL);
assert(mybm != NULL);
HGDIOBJ orig = SelectObject(mydc, mybm); // error raised
SelectObject(mydc, orig);
DeleteObject(mybm);
return 0;
}
static unsigned int WINAPI
thread_release(void *arg)
{
HDC dc = (HDC) arg;
assert(dc != NULL);
ReleaseDC(NULL, dc); // error raised
return 0;
}
static void
test_DC_threads(void)
{
unsigned int tid;
HANDLE thread;
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
// Test DrMem check for: CreateCompatibleDC is not used after creating thread exits
HDC dupdc = NULL; // MSDN says this is bad only for dup of NULL
thread = (HANDLE) _beginthreadex(NULL, 0, thread_dup_DC, (void*)&dupdc, 0, &tid);
WaitForSingleObject(thread, INFINITE);
HBITMAP mybm = CreateCompatibleBitmap(dupdc, 30, 30);
assert(mybm != NULL);
HGDIOBJ orig = SelectObject(dupdc, mybm); // error raised
assert(orig != NULL);
SelectObject(dupdc, orig); // error raised
DeleteDC(dupdc);
DeleteObject(mybm);
// Ensure no error when duplicated from other than NULL
dupdc = mydc;
thread = (HANDLE) _beginthreadex(NULL, 0, thread_dup_DC, (void*)&dupdc, 0, &tid);
WaitForSingleObject(thread, INFINITE);
mybm = CreateCompatibleBitmap(dupdc, 30, 30);
assert(mybm != NULL);
orig = SelectObject(dupdc, mybm);
assert(orig != NULL);
SelectObject(dupdc, orig); // Should have no error raised!
DeleteDC(dupdc);
DeleteObject(mybm);
// Test DrMem check for: do not operate on a single DC from two different threads
// we need a memory DC to select a bitmap into
dupdc = CreateCompatibleDC(mydc);
assert(dupdc != NULL);
mybm = CreateCompatibleBitmap(dupdc, 16, 16);
assert(mybm != NULL);
orig = SelectObject(dupdc, mybm);
assert(orig != NULL);
SelectObject(dupdc, orig);
thread = (HANDLE) _beginthreadex(NULL, 0, thread_select, (void*)dupdc, 0, &tid);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
DeleteObject(mybm);
DeleteDC(dupdc);
// Test DrMem check for: ReleaseDC called from the same thread that called GetDC
thread = (HANDLE) _beginthreadex(NULL, 0, thread_release, (void*)mydc, 0, &tid);
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
}
static void
test_DC_objdel(void)
{
// Test DrMem check for: do not delete HGDIOBJ that is selected in any DC
HPEN mypen = CreatePen(PS_SOLID, 0xab,RGB(0xab,0xcd,0xef));
assert(mypen != NULL);
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
HGDIOBJ orig = SelectObject(mydc, mypen);
DeleteObject(mypen); // error raised
SelectObject(mydc, orig);
// we need a memory DC to select a bitmap into
HDC dupdc = CreateCompatibleDC(mydc);
assert(dupdc != NULL);
HBITMAP mybm = CreateCompatibleBitmap(dupdc, 30, 30);
assert(mybm != NULL);
orig = SelectObject(dupdc, mybm);
assert(orig != NULL);
DeleteObject(mybm); // no error raised since not a drawing object (i#899)
SelectObject(dupdc, orig);
DeleteDC(dupdc);
ReleaseDC(NULL, mydc);
}
static void
test_DC_bitmap(void)
{
// Test DrMem check for: do not select the same bitmap into two different DC's
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
// we need a memory DC to select a bitmap into
HDC dupdcA = CreateCompatibleDC(mydc);
assert(dupdcA != NULL);
HDC dupdcB = CreateCompatibleDC(mydc);
assert(dupdcB != NULL);
HBITMAP mybm = CreateCompatibleBitmap(dupdcA, 30, 30);
assert(mybm != NULL);
HGDIOBJ orig = SelectObject(dupdcA, mybm);
assert(orig != NULL);
orig = SelectObject(dupdcB, mybm); // error raised
// not asserting b/c orig is NULL on win7
DeleteDC(dupdcA); // error raised
DeleteDC(dupdcB);
ReleaseDC(NULL, mydc);
}
static void
test_DC_select(void)
{
// Test DrMem check for: non-default objects selected in a DC being deleted
// (N.B. (i#764): need to intercept library routine to see pen selection)
HPEN mypen = CreatePen(PS_SOLID, 0xab,RGB(0xab,0xcd,0xef));
assert(mypen != NULL);
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
HDC dupdc = CreateCompatibleDC(mydc);
assert(dupdc != NULL);
SelectObject(dupdc, mypen);
DeleteDC(dupdc); // error raised
DeleteObject(mypen); // error raised
ReleaseDC(NULL, mydc);
}
static void
test_suppress(void)
{
// duplicate of test_objdel but suppressed
HPEN mypen = CreatePen(PS_SOLID, 0xab,RGB(0xab,0xcd,0xef));
assert(mypen != NULL);
HDC mydc = GetDC(NULL);
assert(mydc != NULL);
HGDIOBJ orig = SelectObject(mydc, mypen);
DeleteObject(mypen); // error raised
SelectObject(mydc, orig);
}
int CALLBACK
EnumFontFamExProc(const LOGFONT *lpelfe,
const TEXTMETRIC *lpntme,
DWORD FontType,
LPARAM lParam)
{
return 0; /* stop enumeration */
}
static void
test_EnumFont()
{
HDC mydc = GetDC(NULL);
LOGFONT logfont;
/* test i#502 */
logfont.lfCharSet = DEFAULT_CHARSET;
logfont.lfFaceName[0] = '\0';
logfont.lfPitchAndFamily = 0;
EnumFontFamiliesEx(mydc, &logfont, EnumFontFamExProc, NULL, 0);
ReleaseDC(NULL, mydc);
}
int
main()
{
test_DC_free();
test_DC_threads();
test_DC_objdel();
test_DC_bitmap();
test_DC_select();
test_suppress();
test_EnumFont();
return 0;
}