diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index 91e04b9fb58..21b82d9eadc 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -33,6 +33,7 @@ #include "wingdi.h" #include "winuser.h" #include "winerror.h" +#include "ntstatus.h" #include "wownt32.h" #include "wine/wingdi16.h" @@ -138,9 +139,9 @@ static int clip_children( HWND parent, HWND last, HRGN hrgn, int whole_window ) static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags ) { RGNDATA *data; + NTSTATUS status; HRGN ret = 0; size_t size = 256; - BOOL retry = FALSE; do { @@ -151,28 +152,22 @@ static HRGN get_server_visible_region( HWND hwnd, HWND top, UINT flags ) req->top_win = top; req->flags = flags; wine_server_set_reply( req, data->Buffer, size ); - if (!wine_server_call_err( req )) + if (!(status = wine_server_call( req ))) { - if (reply->total_size <= size) - { - size_t reply_size = wine_server_reply_size( reply ); - data->rdh.dwSize = sizeof(data->rdh); - data->rdh.iType = RDH_RECTANGLES; - data->rdh.nCount = reply_size / sizeof(RECT); - data->rdh.nRgnSize = reply_size; - ret = ExtCreateRegion( NULL, size, data ); - retry = FALSE; - } - else - { - size = reply->total_size; - retry = TRUE; - } + size_t reply_size = wine_server_reply_size( reply ); + data->rdh.dwSize = sizeof(data->rdh); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = reply_size / sizeof(RECT); + data->rdh.nRgnSize = reply_size; + ret = ExtCreateRegion( NULL, size, data ); } + else size = reply->total_size; } SERVER_END_REQ; HeapFree( GetProcessHeap(), 0, data ); - } while (retry); + } while (status == STATUS_BUFFER_OVERFLOW); + + if (status) SetLastError( RtlNtStatusToDosError(status) ); return ret; } diff --git a/server/region.c b/server/region.c index 2604b4c8389..c72089a533e 100644 --- a/server/region.c +++ b/server/region.c @@ -618,19 +618,23 @@ void set_region_rect( struct region *region, const rectangle_t *rect ) } /* retrieve the region data for sending to the client */ -rectangle_t *get_region_data( const struct region *region, size_t *total_size ) +rectangle_t *get_region_data( const struct region *region, size_t max_size, size_t *total_size ) { + const rectangle_t *data = region->rects; + if (!(*total_size = region->num_rects * sizeof(rectangle_t))) { /* return a single empty rect for empty regions */ *total_size = sizeof(empty_rect); - return memdup( &empty_rect, sizeof(empty_rect) ); + data = &empty_rect; } - return memdup( region->rects, *total_size ); + if (max_size >= *total_size) return memdup( data, *total_size ); + set_error( STATUS_BUFFER_OVERFLOW ); + return NULL; } /* retrieve the region data for sending to the client and free the region at the same time */ -rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size ) +rectangle_t *get_region_data_and_free( struct region *region, size_t max_size, size_t *total_size ) { rectangle_t *ret = region->rects; @@ -638,7 +642,18 @@ rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size { /* return a single empty rect for empty regions */ *total_size = sizeof(empty_rect); - ret = memdup( &empty_rect, sizeof(empty_rect) ); + if (max_size >= sizeof(empty_rect)) + { + ret = memdup( &empty_rect, sizeof(empty_rect) ); + free( region->rects ); + } + } + + if (max_size < *total_size) + { + free( region->rects ); + set_error( STATUS_BUFFER_OVERFLOW ); + ret = NULL; } free( region ); return ret; diff --git a/server/user.h b/server/user.h index 2857d41f1c6..7488c73d637 100644 --- a/server/user.h +++ b/server/user.h @@ -71,8 +71,10 @@ extern struct region *create_region( const rectangle_t *rects, unsigned int nb_r extern struct region *create_region_from_req_data( const void *data, size_t size ); extern void free_region( struct region *region ); extern void set_region_rect( struct region *region, const rectangle_t *rect ); -extern rectangle_t *get_region_data( const struct region *region, size_t *total_size ); -extern rectangle_t *get_region_data_and_free( struct region *region, size_t *total_size ); +extern rectangle_t *get_region_data( const struct region *region, size_t max_size, + size_t *total_size ); +extern rectangle_t *get_region_data_and_free( struct region *region, size_t max_size, + size_t *total_size ); extern int is_region_empty( const struct region *region ); extern void get_region_extents( const struct region *region, rectangle_t *rect ); extern void offset_region( struct region *region, int x, int y ); diff --git a/server/window.c b/server/window.c index 00a004eff56..1b069870b41 100644 --- a/server/window.c +++ b/server/window.c @@ -1084,8 +1084,8 @@ DECL_HANDLER(get_visible_region) if ((region = get_visible_region( win, top, req->flags ))) { - rectangle_t *data = get_region_data_and_free( region, &reply->total_size ); - set_reply_data_ptr( data, min(reply->total_size,get_reply_max_size()) ); + rectangle_t *data = get_region_data_and_free( region, get_reply_max_size(), &reply->total_size ); + if (data) set_reply_data_ptr( data, reply->total_size ); } } @@ -1097,11 +1097,10 @@ DECL_HANDLER(get_window_region) if (!win) return; - reply->total_size = 0; if (win->win_region) { - rectangle_t *data = get_region_data( win->win_region, &reply->total_size ); - set_reply_data_ptr( data, min( reply->total_size, get_reply_max_size() ) ); + rectangle_t *data = get_region_data( win->win_region, get_reply_max_size(), &reply->total_size ); + if (data) set_reply_data_ptr( data, reply->total_size ); } } diff --git a/windows/winpos.c b/windows/winpos.c index 3e0f8f69d9c..c0ebb3ff6f6 100644 --- a/windows/winpos.c +++ b/windows/winpos.c @@ -29,6 +29,7 @@ #include "winbase.h" #include "wingdi.h" #include "winerror.h" +#include "ntstatus.h" #include "wine/winuser16.h" #include "wine/server.h" #include "controls.h" @@ -172,10 +173,10 @@ BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect ) int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn ) { int nRet = ERROR; + NTSTATUS status; HRGN win_rgn = 0; RGNDATA *data; size_t size = 256; - BOOL retry = FALSE; do { @@ -188,31 +189,26 @@ int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn ) { req->window = hwnd; wine_server_set_reply( req, data->Buffer, size ); - if (!wine_server_call_err( req )) + if (!(status = wine_server_call( req ))) { - if (!reply->total_size) retry = FALSE; /* no region at all */ - else if (reply->total_size <= size) + size_t reply_size = wine_server_reply_size( reply ); + if (reply_size) { - size_t reply_size = wine_server_reply_size( reply ); data->rdh.dwSize = sizeof(data->rdh); data->rdh.iType = RDH_RECTANGLES; data->rdh.nCount = reply_size / sizeof(RECT); data->rdh.nRgnSize = reply_size; win_rgn = ExtCreateRegion( NULL, size, data ); - retry = FALSE; - } - else - { - size = reply->total_size; - retry = TRUE; } } + else size = reply->total_size; } SERVER_END_REQ; HeapFree( GetProcessHeap(), 0, data ); - } while (retry); + } while (status == STATUS_BUFFER_OVERFLOW); - if (win_rgn) + if (status) SetLastError( RtlNtStatusToDosError(status) ); + else if (win_rgn) { nRet = CombineRgn( hrgn, win_rgn, 0, RGN_COPY ); DeleteObject( win_rgn );