From: Jacek Caban Subject: [PATCH] user32: Make sure that passed window handle is scroll control before accessing wExtra in SCROLL_GetInternalInfo. Message-Id: <3f3ae2b4-0514-ad7a-816f-20c1f6499371@codeweavers.com> Date: Wed, 12 Sep 2018 14:52:42 +0200 Fixes memory corruption in Office 2016. Signed-off-by: Jacek Caban --- I'm not sure a new window flag is the best way to handle it. I did it the same way as it's done for MDI client. dlls/user32/scroll.c | 7 ++++++- dlls/user32/tests/scroll.c | 21 +++++++++++++++++++++ dlls/user32/win.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c index 1c127fbc71..4b45566eb1 100644 --- a/dlls/user32/scroll.c +++ b/dlls/user32/scroll.c @@ -159,7 +159,10 @@ static SCROLLBAR_INFO *SCROLL_GetInternalInfo( HWND hwnd, INT nBar, BOOL alloc ) if (wndPtr->pScroll) infoPtr = &((LPWINSCROLLBAR_INFO)wndPtr->pScroll)->vert; break; case SB_CTL: - infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; + if (wndPtr->flags & WIN_ISSCROLL) + infoPtr = (SCROLLBAR_INFO *)wndPtr->wExtra; + else + WARN( "WB_CTL used on a window %p that is not a scroll control\n", hwnd ); break; case SB_BOTH: WARN("with SB_BOTH\n"); @@ -1393,6 +1396,8 @@ LRESULT ScrollBarWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM { if (!IsWindow( hwnd )) return 0; + if (message == WM_NCCREATE) win_set_flags( hwnd, WIN_ISSCROLL, 0 ); + switch(message) { case WM_CREATE: diff --git a/dlls/user32/tests/scroll.c b/dlls/user32/tests/scroll.c index 291d11af0f..c19607d9f2 100644 --- a/dlls/user32/tests/scroll.c +++ b/dlls/user32/tests/scroll.c @@ -114,6 +114,14 @@ static void test_EnableScrollBar(void) ok( ret, "The scrollbar should be enabled.\n" ); ok( IsWindowEnabled( hScroll ), "The scrollbar window should be enabled.\n" ); + SetLastError( 0xdeadbeef ); + ret = EnableScrollBar( mainwnd, SB_CTL, ESB_ENABLE_BOTH ); + ok( !ret, "EnableScrollBar should fail.\n" ); + todo_wine + ok( GetLastError() == ERROR_INVALID_PARAMETER + || broken(GetLastError() == 0xdeadbeef), /* winxp */ + "GetLastError() = %u\n", GetLastError() ); + /* disable window, try to re-enable */ ret = EnableWindow( hScroll, FALSE ); ok( !ret, "got %d\n", ret ); @@ -170,6 +178,16 @@ static void test_SetScrollPos(void) ret = GetScrollPos( hScroll, SB_CTL); ok( ret == 30, "The position should not be equal to zero\n"); + SetLastError( 0xdeadbeef ); + ret = SetScrollPos( mainwnd, SB_CTL, 30, TRUE ); + ok( !ret, "The position should not be set.\n" ); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %u\n", GetLastError() ); + + SetLastError( 0xdeadbeef ); + ret = GetScrollPos( mainwnd, SB_CTL ); + ok( !ret, "The position should be equal to zero\n"); + ok( GetLastError() == 0xdeadbeef, "GetLastError() = %u\n", GetLastError() ); + DestroyWindow(hScroll); DestroyWindow(mainwnd); } @@ -192,6 +210,9 @@ static void test_ShowScrollBar(void) ret = ShowScrollBar( NULL, SB_CTL, TRUE ); ok( !ret, "The ShowScrollBar() should failed.\n" ); + ret = ShowScrollBar( mainwnd, SB_CTL, TRUE ); + ok( ret, "The ShowScrollBar() should not fail.\n" ); + DestroyWindow(hScroll); DestroyWindow(mainwnd); } diff --git a/dlls/user32/win.h b/dlls/user32/win.h index f3bdfd38d9..1b90f957b9 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -80,6 +80,7 @@ typedef struct tagWND #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0020 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ #define WIN_CHILDREN_MOVED 0x0040 /* children may have moved, ignore stored positions */ #define WIN_HAS_IME_WIN 0x0080 /* the window has been registered with imm32 */ +#define WIN_ISSCROLL 0x0100 /* window is a scroll control */ /* Window functions */ extern HWND get_hwnd_message_parent(void) DECLSPEC_HIDDEN;