From 23edf2c2b89b98ef18849806e74b5d77f7889160 Mon Sep 17 00:00:00 2001 From: Daniel Lehman Date: Wed, 25 Jan 2012 13:47:31 -0800 Subject: gdi32/dibdrv: don't add_join if points are coincident in wide_line_segments if 2 points coincide (dx == dy == 0), wide_line_segments returns immediately in that case, face_1 is not changed. it is not initialized so junk values on the stack are used. when passed to add_join they create a region that causes a huge amount of memory to be allocated. depending on the values, all available/rlimit memory is exhausted and the program crashes. reverting to 1.3.26 works fine the test case submitted is a drastically reduced, simplest possible form of what our internal test does, based on real map data relevant debugging information: Thread 22 (Thread 0x41090940 (LWP 7592)): round_cap=0x0, total=0x6094) at dibdrv/objects.c:1490 counts[0] = 84 counts[1] = 4 counts[2] = 8 pt[0] = {x = 628, y = 616} pt[1] = {x = 629, y = 620} pt[2] = {x = 629, y = 620} ... (gdb) fr 3 round_cap=0x0, total=0x6094) at dibdrv/objects.c:1490 1490 add_join( pdev, total, round_cap, pt_1, &prev_face, &face_1 ); (gdb) p i $54 = 1 (gdb) p face_1 $55 = { start = { x = 0, y = 1082501120 }, end = { x = 148503616, y = 0 }, dx = 0, dy = 0 } --- dlls/gdi32/dibdrv/objects.c | 16 ++++++++----- dlls/gdi32/tests/dib.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 6 deletions(-) mode change 100644 => 100755 dlls/gdi32/tests/dib.c diff --git a/dlls/gdi32/dibdrv/objects.c b/dlls/gdi32/dibdrv/objects.c index a9d6ca5..6e31d6f 100644 --- a/dlls/gdi32/dibdrv/objects.c +++ b/dlls/gdi32/dibdrv/objects.c @@ -1327,7 +1327,7 @@ static void add_join( dibdrv_physdev *pdev, HRGN region, HRGN round_cap, const P return; } -static void wide_line_segment( dibdrv_physdev *pdev, HRGN total, +static int wide_line_segment( dibdrv_physdev *pdev, HRGN total, const POINT *pt_1, const POINT *pt_2, int dx, int dy, BOOL need_cap_1, BOOL need_cap_2, struct face *face_1, struct face *face_2 ) { @@ -1335,7 +1335,7 @@ static void wide_line_segment( dibdrv_physdev *pdev, HRGN total, BOOL sq_cap_1 = need_cap_1 && (pdev->pen_endcap == PS_ENDCAP_SQUARE); BOOL sq_cap_2 = need_cap_2 && (pdev->pen_endcap == PS_ENDCAP_SQUARE); - if (dx == 0 && dy == 0) return; + if (dx == 0 && dy == 0) return 0; if (dy == 0) { @@ -1451,6 +1451,8 @@ static void wide_line_segment( dibdrv_physdev *pdev, HRGN total, face_1->dx = face_2->dx = dx; face_1->dy = face_2->dy = dy; + + return 1; } static void wide_line_segments( dibdrv_physdev *pdev, int num, const POINT *pts, BOOL close, @@ -1486,10 +1488,12 @@ static void wide_line_segments( dibdrv_physdev *pdev, int num, const POINT *pts, { pt_1 = &pts[(start + i) % num]; pt_2 = &pts[(start + i + 1) % num]; - wide_line_segment( pdev, total, pt_1, pt_2, pt_2->x - pt_1->x, pt_2->y - pt_1->y, - FALSE, FALSE, &face_1, &face_2 ); - add_join( pdev, total, round_cap, pt_1, &prev_face, &face_1 ); - prev_face = face_2; + if (wide_line_segment( pdev, total, pt_1, pt_2, pt_2->x - pt_1->x, pt_2->y - pt_1->y, + FALSE, FALSE, &face_1, &face_2 )) + { + add_join( pdev, total, round_cap, pt_1, &prev_face, &face_1 ); + prev_face = face_2; + } } pt_1 = &pts[(start + count - 1) % num]; diff --git a/dlls/gdi32/tests/dib.c b/dlls/gdi32/tests/dib.c old mode 100644 new mode 100755 index 0102115..d7b7546 --- a/dlls/gdi32/tests/dib.c +++ b/dlls/gdi32/tests/dib.c @@ -3171,6 +3171,54 @@ static void test_simple_graphics(void) DeleteDC(mem_dc); } +static void test_coincident_points(void) +{ + const DWORD counts[] = { 4 }; + const POINT points[4] = + { + { 0, 0 }, + { 1, 1 }, + { 1, 1 }, + { 1, 2 } + }; + HDC mem_dc; + HBITMAP bmp; + HBITMAP orig_bmp; + LPBYTE bits; + BITMAPINFO bmi; + HPEN wide_pen; + HPEN orig_pen; + LOGBRUSH log_brush; + + mem_dc = CreateCompatibleDC( 0 ); + + memset( &bmi, 0, sizeof( bmi ) ); + bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); + bmi.bmiHeader.biWidth = 1024; + bmi.bmiHeader.biHeight = 1024; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; + bmp = CreateDIBSection( mem_dc, &bmi, DIB_RGB_COLORS, (void **)&bits, NULL, 0 ); + + log_brush.lbStyle = BS_SOLID; + log_brush.lbColor = RGB(0xff, 0, 0); + log_brush.lbHatch = 0; + + wide_pen = ExtCreatePen( PS_GEOMETRIC | PS_ENDCAP_FLAT | PS_JOIN_MITER | PS_SOLID, + 9, &log_brush, 0, NULL ); + + orig_bmp = (HBITMAP)SelectObject( mem_dc, bmp ); + orig_pen = (HPEN)SelectObject( mem_dc, wide_pen ); + ok(PolyPolyline( mem_dc, points, counts, sizeof(counts)/sizeof(counts[0]) ), "PolyPolyline failed"); + + SelectObject( mem_dc, orig_pen ); + SelectObject( mem_dc, orig_bmp ); + DeleteObject( bmp); + + DeleteDC(mem_dc); +} + START_TEST(dib) { HMODULE mod = GetModuleHandleA("gdi32.dll"); @@ -3181,6 +3229,7 @@ START_TEST(dib) CryptAcquireContextW(&crypt_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); test_simple_graphics(); + test_coincident_points(); CryptReleaseContext(crypt_prov, 0); } -- 1.6.0.4