-- v4: win32u: Read extra class info from the shared memory object. server: Move extra class info to the shared memory object. server: Allocate shared memory objects with dynamic size. win32u: Read class info from the shared memory object. server: Move class info to the shared memory object.
From: Rémi Bernon rbernon@codeweavers.com
--- server/class.c | 112 ++++++++++++++++++++++---------------------- server/protocol.def | 4 ++ 2 files changed, 61 insertions(+), 55 deletions(-)
diff --git a/server/class.c b/server/class.c index 098acf8c041..de2c4ee429c 100644 --- a/server/class.c +++ b/server/class.c @@ -46,19 +46,15 @@ struct window_class struct process *process; /* process owning the class */ int count; /* reference count */ int local; /* local class? */ - atom_t atom; /* class atom */ - atom_t base_atom; /* base class atom for versioned class */ - mod_handle_t instance; /* module instance */ - unsigned int style; /* class style */ - int win_extra; /* number of window extra bytes */ + atom_t atom; /* class atom for versioned class */ client_ptr_t client_ptr; /* pointer to class in client address space */ class_shm_t *shared; /* class in session shared memory */ int nb_extra_bytes; /* number of extra bytes */ char extra_bytes[1]; /* extra bytes storage */ };
-static struct window_class *create_class( struct process *process, int extra_bytes, int local, - struct unicode_str *name, unsigned int name_offset ) +static struct window_class *create_class( struct process *process, int extra_bytes, int local, struct unicode_str *name, unsigned int name_offset, + atom_t atom, mod_handle_t instance, unsigned int style, int win_extra ) { struct window_class *class;
@@ -74,8 +70,12 @@ static struct window_class *create_class( struct process *process, int extra_byt SHARED_WRITE_BEGIN( class->shared, class_shm_t ) { memcpy( (void *)shared->name, name->str, name->len ); - shared->name_offset = name_offset; - shared->name_len = name->len; + shared->name_offset = name_offset; + shared->name_len = name->len; + shared->atom = atom; + shared->instance = instance; + shared->style = style; + shared->win_extra = win_extra; } SHARED_WRITE_END;
@@ -96,7 +96,7 @@ static void destroy_class( struct window_class *class ) struct atom_table *table = get_user_atom_table();
release_atom( table, class->atom ); - release_atom( table, class->base_atom ); + release_atom( table, class->shared->atom ); list_remove( &class->entry ); release_object( class->process ); if (class->shared) free_shared_object( class->shared ); @@ -121,10 +121,11 @@ static struct window_class *find_class( struct process *process, atom_t atom, mo
LIST_FOR_EACH_ENTRY( class, &process->classes, struct window_class, entry ) { + const class_shm_t *shared = class->shared; if (class->atom != atom) continue; - is_win16 = !(class->instance >> 16); - if (!instance || !class->local || class->instance == instance || - (!is_win16 && ((class->instance & ~0xffff) == (instance & ~0xffff)))) return class; + is_win16 = !(shared->instance >> 16); + if (!instance || !class->local || shared->instance == instance || + (!is_win16 && ((shared->instance & ~0xffff) == (instance & ~0xffff)))) return class; } return NULL; } @@ -136,7 +137,7 @@ struct window_class *grab_class( struct process *process, atom_t atom, mod_handl if (class) { class->count++; - *extra_bytes = class->win_extra; + *extra_bytes = class->shared->win_extra; *locator = get_shared_object_locator( class->shared ); } else set_error( STATUS_INVALID_HANDLE ); @@ -151,7 +152,7 @@ void release_class( struct window_class *class )
int is_desktop_class( struct window_class *class ) { - return (class->atom == DESKTOP_ATOM && !class->local); + return (class->shared->atom == DESKTOP_ATOM && !class->local); }
int is_message_class( struct window_class *class ) @@ -160,17 +161,17 @@ int is_message_class( struct window_class *class ) static const struct unicode_str name = { messageW, sizeof(messageW) }; struct atom_table *table = get_user_atom_table();
- return (!class->local && class->atom == find_atom( table, &name )); + return (!class->local && class->shared->atom == find_atom( table, &name )); }
int get_class_style( struct window_class *class ) { - return class->style; + return class->shared->style; }
atom_t get_class_atom( struct window_class *class ) { - return class->base_atom; + return class->shared->atom; }
client_ptr_t get_class_client_ptr( struct window_class *class ) @@ -238,17 +239,14 @@ DECL_HANDLER(create_class) return; }
- if (!(class = create_class( current->process, req->extra, req->local, &name, offset ))) + if (!(class = create_class( current->process, req->extra, req->local, &name, offset, + base_atom, req->instance, req->style, req->win_extra ))) { release_atom( table, atom ); release_atom( table, base_atom ); return; } class->atom = atom; - class->base_atom = base_atom; - class->instance = req->instance; - class->style = req->style; - class->win_extra = req->win_extra; class->client_ptr = req->client_ptr; reply->locator = get_shared_object_locator( class->shared ); reply->atom = base_atom; @@ -289,39 +287,43 @@ DECL_HANDLER(set_class_info) return; }
- switch (req->offset) + SHARED_WRITE_BEGIN( class->shared, class_shm_t ) { - case GCL_STYLE: - reply->old_info = class->style; - class->style = req->new_info; - break; - case GCL_CBWNDEXTRA: - if (req->new_info > 4096) - { - set_error( STATUS_INVALID_PARAMETER ); - return; - } - reply->old_info = class->win_extra; - class->win_extra = req->new_info; - break; - case GCL_CBCLSEXTRA: - set_win32_error( ERROR_INVALID_INDEX ); - break; - case GCLP_HMODULE: - reply->old_info = class->instance; - class->instance = req->new_info; - break; - default: - if (req->size > sizeof(req->new_info) || req->offset < 0 || - req->offset > class->nb_extra_bytes - (int)req->size) + switch (req->offset) { + case GCL_STYLE: + reply->old_info = shared->style; + shared->style = req->new_info; + break; + case GCL_CBWNDEXTRA: + if (req->new_info > 4096) + { + set_error( STATUS_INVALID_PARAMETER ); + return; + } + reply->old_info = shared->win_extra; + shared->win_extra = req->new_info; + break; + case GCL_CBCLSEXTRA: set_win32_error( ERROR_INVALID_INDEX ); - return; + break; + case GCLP_HMODULE: + reply->old_info = shared->instance; + shared->instance = req->new_info; + break; + default: + if (req->size > sizeof(req->new_info) || req->offset < 0 || + req->offset > class->nb_extra_bytes - (int)req->size) + { + set_win32_error( ERROR_INVALID_INDEX ); + return; + } + memcpy( &reply->old_info, class->extra_bytes + req->offset, req->size ); + memcpy( class->extra_bytes + req->offset, &req->new_info, req->size ); + break; } - memcpy( &reply->old_info, class->extra_bytes + req->offset, req->size ); - memcpy( class->extra_bytes + req->offset, &req->new_info, req->size ); - break; } + SHARED_WRITE_END; }
@@ -343,11 +345,11 @@ DECL_HANDLER(get_class_info) /* not supported */ set_win32_error( ERROR_INVALID_HANDLE ); break; - case GCL_STYLE: reply->info = class->style; break; - case GCL_CBWNDEXTRA: reply->info = class->win_extra; break; + case GCL_STYLE: reply->info = class->shared->style; break; + case GCL_CBWNDEXTRA: reply->info = class->shared->win_extra; break; case GCL_CBCLSEXTRA: reply->info = class->nb_extra_bytes; break; - case GCLP_HMODULE: reply->info = class->instance; break; - case GCW_ATOM: reply->info = class->atom; break; + case GCLP_HMODULE: reply->info = class->shared->instance; break; + case GCW_ATOM: reply->info = class->shared->atom; break; default: if (req->size > sizeof(reply->info) || req->offset < 0 || req->offset > class->nb_extra_bytes - (int)req->size) diff --git a/server/protocol.def b/server/protocol.def index c9c77b1cf17..37c5e8be83f 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1039,6 +1039,10 @@ typedef volatile struct
typedef volatile struct { + atom_t atom; /* class atom */ + unsigned int style; /* class style */ + unsigned int win_extra; /* number of window extra bytes */ + mod_handle_t instance; /* module instance */ data_size_t name_offset; /* offset in WCHAR of the unversioned class name, constant */ data_size_t name_len; /* len in bytes of the class name, constant */ WCHAR name[MAX_ATOM_LEN]; /* class name, constant */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 152 +++++++++++++++++++++++++++++--------------- server/class.c | 4 -- 2 files changed, 101 insertions(+), 55 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 57e18cbfc18..493079908aa 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -47,19 +47,15 @@ SYSTEM_BASIC_INFORMATION system_info; typedef struct tagCLASS { struct list entry; /* Entry in class list */ - UINT style; /* Class style */ BOOL local; /* Local class? */ WNDPROC winproc; /* Window procedure */ INT cbClsExtra; /* Class extra bytes */ - INT cbWndExtra; /* Window extra bytes */ struct dce *dce; /* Opaque pointer to class DCE */ - UINT_PTR instance; /* Module that created the task */ HICON hIcon; /* Default icon */ HICON hIconSm; /* Default small icon */ HICON hIconSmIntern; /* Internal small icon, derived from hIcon */ HCURSOR hCursor; /* Default cursor */ HBRUSH hbrBackground; /* Default background */ - ATOM atom; /* name of the class */ struct client_menu_name menu_name; /* Default menu name */ const shared_object_t *shared; /* class object in session shared memory */ } CLASS; @@ -389,6 +385,25 @@ static CLASS *get_class_ptr( HWND hwnd, BOOL write_access ) return NULL; }
+static NTSTATUS get_shared_class( CLASS *class, struct object_lock *lock, const class_shm_t **class_shm ) +{ + const shared_object_t *object; + + TRACE( "class %p, lock %p, class_shm %p\n", class, lock, class_shm ); + + if (!(object = class->shared)) return STATUS_INVALID_HANDLE; + + if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) + { + shared_object_acquire_seqlock( object, &lock->seq ); + *class_shm = &object->shm.class; + lock->id = object->id; + return STATUS_PENDING; + } + + return STATUS_SUCCESS; +} + static NTSTATUS get_shared_window_class( HWND hwnd, struct object_lock *lock, const class_shm_t **class_shm ) { const shared_object_t *object; @@ -430,6 +445,19 @@ static BOOL class_name_matches( CLASS *class, UNICODE_STRING *name ) return name->Length == len && !wcsnicmp( class_name, name->Buffer, len / sizeof(WCHAR) ); }
+static UINT_PTR get_class_instance( CLASS *class ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const class_shm_t *class_shm; + UINT_PTR instance = 0; + NTSTATUS status; + + while ((status = get_shared_class( class, &lock, &class_shm )) == STATUS_PENDING) + instance = class_shm->instance; + if (status) return 0; + return instance; +} + static CLASS *find_class( HINSTANCE module, UNICODE_STRING *name ) { ULONG_PTR instance = (UINT_PTR)module; @@ -439,10 +467,11 @@ static CLASS *find_class( HINSTANCE module, UNICODE_STRING *name ) user_lock(); LIST_FOR_EACH_ENTRY( class, &class_list, CLASS, entry ) { + UINT_PTR class_instance = get_class_instance( class ); if (!class_name_matches( class, name )) continue; - is_win16 = !(class->instance >> 16); - if (!instance || !class->local || class->instance == instance || - (!is_win16 && ((class->instance & ~0xffff) == (instance & ~0xffff)))) + is_win16 = !(class_instance >> 16); + if (!instance || !class->local || class_instance == instance || + (!is_win16 && ((class_instance & ~0xffff) == (instance & ~0xffff)))) { TRACE( "%s %lx -> %p\n", debugstr_us(name), instance, class ); return class; @@ -517,19 +546,16 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
if (!(class = calloc( 1, sizeof(CLASS) + wc->cbClsExtra ))) return 0;
- class->style = wc->style; class->local = !is_builtin && !(wc->style & CS_GLOBALCLASS); - class->cbWndExtra = wc->cbWndExtra; class->cbClsExtra = wc->cbClsExtra; - class->instance = (UINT_PTR)instance;
SERVER_START_REQ( create_class ) { req->local = class->local; - req->style = class->style; - req->instance = class->instance; + req->style = wc->style; + req->instance = wine_server_client_ptr( instance ); req->extra = class->cbClsExtra; - req->win_extra = class->cbWndExtra; + req->win_extra = wc->cbWndExtra; req->client_ptr = wine_server_client_ptr( class ); req->atom = wine_server_add_atom( req, name ); req->name_offset = version->Length / sizeof(WCHAR); @@ -578,7 +604,6 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam class->hIconSmIntern = sm_icon; class->hCursor = wc->hCursor; class->hbrBackground = wc->hbrBackground; - class->atom = atom; class->winproc = alloc_winproc( wc->lpfnWndProc, ansi ); if (client_menu_name) class->menu_name = *client_menu_name; class->shared = shared; @@ -626,31 +651,38 @@ BOOL WINAPI NtUserUnregisterClass( UNICODE_STRING *name, HINSTANCE instance, ATOM WINAPI NtUserGetClassInfoEx( HINSTANCE instance, UNICODE_STRING *name, WNDCLASSEXW *wc, struct client_menu_name *menu_name, BOOL ansi ) { + struct object_lock lock = OBJECT_LOCK_INIT; + const class_shm_t *class_shm; + NTSTATUS status; CLASS *class; - ATOM atom; + ATOM atom = 0;
/* create the desktop window to trigger builtin class registration */ if (!is_desktop_class( name ) && !is_message_class( name )) get_desktop_window();
if (!(class = find_class( instance, name ))) return 0;
- if (wc) + while ((status = get_shared_class( class, &lock, &class_shm )) == STATUS_PENDING) { - wc->style = class->style; - wc->lpfnWndProc = get_winproc( class->winproc, ansi ); - wc->cbClsExtra = class->cbClsExtra; - wc->cbWndExtra = class->cbWndExtra; - wc->hInstance = (instance == user32_module) ? 0 : instance; - wc->hIcon = class->hIcon; - wc->hIconSm = class->hIconSm ? class->hIconSm : class->hIconSmIntern; - wc->hCursor = class->hCursor; - wc->hbrBackground = class->hbrBackground; - wc->lpszMenuName = ansi ? (const WCHAR *)class->menu_name.nameA : class->menu_name.nameW; - wc->lpszClassName = name->Buffer; + if (wc) + { + wc->style = class_shm->style; + wc->lpfnWndProc = get_winproc( class->winproc, ansi ); + wc->cbClsExtra = class->cbClsExtra; + wc->cbWndExtra = class_shm->win_extra; + wc->hInstance = (instance == user32_module) ? 0 : instance; + wc->hIcon = class->hIcon; + wc->hIconSm = class->hIconSm ? class->hIconSm : class->hIconSmIntern; + wc->hCursor = class->hCursor; + wc->hbrBackground = class->hbrBackground; + wc->lpszMenuName = ansi ? (const WCHAR *)class->menu_name.nameA : class->menu_name.nameW; + wc->lpszClassName = name->Buffer; + } + atom = class_shm->atom; } + if (status) return 0;
if (menu_name) *menu_name = class->menu_name; - atom = class->atom; release_class_ptr( class ); return atom; } @@ -767,7 +799,7 @@ INT WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name ) }
/* Set class info with the wine server. */ -static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size ) +static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size, ULONG_PTR *oldval ) { BOOL ret;
@@ -778,6 +810,7 @@ static BOOL set_server_info( HWND hwnd, INT offset, LONG_PTR newval, UINT size ) req->size = size; req->new_info = newval; ret = !wine_server_call_err( req ); + *oldval = reply->old_info; } SERVER_END_REQ; return ret; @@ -793,7 +826,7 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI
if (offset >= 0) { - if (set_server_info( hwnd, offset, newval, size )) + if (set_server_info( hwnd, offset, newval, size, &retval )) { void *ptr = (char *)(class + 1) + offset; memcpy( &retval, ptr, size ); @@ -883,19 +916,13 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI class->hIconSmIntern = small_icon; break; case GCL_STYLE: - if (!set_server_info( hwnd, offset, newval, size )) break; - retval = class->style; - class->style = newval; + if (!set_server_info( hwnd, offset, newval, size, &retval )) break; break; case GCL_CBWNDEXTRA: - if (!set_server_info( hwnd, offset, newval, size )) break; - retval = class->cbWndExtra; - class->cbWndExtra = newval; + if (!set_server_info( hwnd, offset, newval, size, &retval )) break; break; case GCLP_HMODULE: - if (!set_server_info( hwnd, offset, newval, size )) break; - retval = class->instance; - class->instance = newval; + if (!set_server_info( hwnd, offset, newval, size, &retval )) break; break; case GCL_CBCLSEXTRA: /* cannot change this one */ RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); @@ -932,11 +959,46 @@ WORD WINAPI NtUserSetClassWord( HWND hwnd, INT offset, WORD newval ) return set_class_long_size( hwnd, offset, newval, sizeof(WORD), TRUE ); }
+static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const class_shm_t *class_shm; + ULONG_PTR ret = 0; + NTSTATUS status; + + while ((status = get_shared_window_class( hwnd, &lock, &class_shm )) == STATUS_PENDING) + { + switch (offset) + { + case GCW_ATOM: ret = class_shm->atom; break; + case GCL_STYLE: ret = class_shm->style; break; + case GCL_CBWNDEXTRA: ret = class_shm->win_extra; break; + case GCLP_HMODULE: ret = class_shm->instance; break; + } + } + if (status) + { + RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); + return 0; + } + + return ret; +} + static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ansi ) { CLASS *class; ULONG_PTR retvalue = 0;
+ switch (offset) + { + case GCW_ATOM: + case GCL_STYLE: + case GCL_CBWNDEXTRA: + case GCLP_HMODULE: + return get_class_long_shm( hwnd, offset, size, ansi ); + } + if (!(class = get_class_ptr( hwnd, FALSE ))) return 0;
if (class == OBJ_OTHER_PROCESS) @@ -1001,27 +1063,15 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans case GCLP_HICONSM: retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern); break; - case GCL_STYLE: - retvalue = class->style; - break; - case GCL_CBWNDEXTRA: - retvalue = class->cbWndExtra; - break; case GCL_CBCLSEXTRA: retvalue = class->cbClsExtra; break; - case GCLP_HMODULE: - retvalue = class->instance; - break; case GCLP_WNDPROC: retvalue = (ULONG_PTR)get_winproc( class->winproc, ansi ); break; case GCLP_MENUNAME: retvalue = ansi ? (ULONG_PTR)class->menu_name.nameA : (ULONG_PTR)class->menu_name.nameW; break; - case GCW_ATOM: - retvalue = class->atom; - break; default: RtlSetLastWin32Error( ERROR_INVALID_INDEX ); break; diff --git a/server/class.c b/server/class.c index de2c4ee429c..53dd5b5509b 100644 --- a/server/class.c +++ b/server/class.c @@ -345,11 +345,7 @@ DECL_HANDLER(get_class_info) /* not supported */ set_win32_error( ERROR_INVALID_HANDLE ); break; - case GCL_STYLE: reply->info = class->shared->style; break; - case GCL_CBWNDEXTRA: reply->info = class->shared->win_extra; break; case GCL_CBCLSEXTRA: reply->info = class->nb_extra_bytes; break; - case GCLP_HMODULE: reply->info = class->shared->instance; break; - case GCW_ATOM: reply->info = class->shared->atom; break; default: if (req->size > sizeof(reply->info) || req->offset < 0 || req->offset > class->nb_extra_bytes - (int)req->size)
From: Rémi Bernon rbernon@codeweavers.com
--- server/class.c | 2 +- server/file.h | 2 +- server/mapping.c | 28 ++++++++++++++++++++-------- server/queue.c | 8 ++++++-- server/window.c | 2 +- server/winstation.c | 2 +- 6 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/server/class.c b/server/class.c index 53dd5b5509b..a5cd765bc2b 100644 --- a/server/class.c +++ b/server/class.c @@ -66,7 +66,7 @@ static struct window_class *create_class( struct process *process, int extra_byt class->nb_extra_bytes = extra_bytes; memset( class->extra_bytes, 0, extra_bytes );
- if (!(class->shared = alloc_shared_object())) goto failed; + if (!(class->shared = alloc_shared_object( sizeof(*class->shared) ))) goto failed; SHARED_WRITE_BEGIN( class->shared, class_shm_t ) { memcpy( (void *)shared->name, name->str, name->len ); diff --git a/server/file.h b/server/file.h index 567194bf00a..db89602441f 100644 --- a/server/file.h +++ b/server/file.h @@ -195,7 +195,7 @@ extern struct mapping *create_session_mapping( struct object *root, const struct extern void set_session_mapping( struct mapping *mapping );
extern session_shm_t *shared_session; -extern volatile void *alloc_shared_object(void); +extern volatile void *alloc_shared_object( mem_size_t shm_size ); extern void free_shared_object( volatile void *object_shm ); extern void invalidate_shared_object( volatile void *object_shm ); extern struct obj_locator get_shared_object_locator( volatile void *object_shm ); diff --git a/server/mapping.c b/server/mapping.c index c3f57b6394c..937ba95b9a0 100644 --- a/server/mapping.c +++ b/server/mapping.c @@ -242,6 +242,7 @@ struct session_object { struct list entry; /* entry in the session free object list */ mem_size_t offset; /* offset of obj in the session shared mapping */ + mem_size_t size; /* size of obj in the session shared mapping */ shared_object_t obj; /* object actually shared with the client */ };
@@ -1380,31 +1381,41 @@ static struct session_block *find_free_session_block( mem_size_t size ) return grow_session_mapping( size ); }
-volatile void *alloc_shared_object(void) +static struct session_object *find_free_session_object( mem_size_t size ) { struct session_object *object; - struct list *ptr;
- if ((ptr = list_head( &session.free_objects ))) + LIST_FOR_EACH_ENTRY( object, &session.free_objects, struct session_object, entry ) { - object = CONTAINING_RECORD( ptr, struct session_object, entry ); - list_remove( &object->entry ); + if (size == sizeof(*object) && object->size == size) return object; + if (size > sizeof(*object) && size <= object->size) return object; } + + return NULL; +} + +volatile void *alloc_shared_object( mem_size_t shm_size ) +{ + struct session_object *object; + mem_size_t size = sizeof(*object) - sizeof(object_shm_t) + max(shm_size, sizeof(object_shm_t)); + + if ((object = find_free_session_object( size ))) + list_remove( &object->entry ); else { - mem_size_t size = sizeof(*object); struct session_block *block;
if (!(block = find_free_session_block( size ))) return NULL; object = (struct session_object *)(block->data + block->used_size); object->offset = block->offset + (char *)&object->obj - block->data; + object->size = size; block->used_size += size; }
SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) { /* mark the object data as uninitialized */ - mark_block_uninitialized( (void *)shared, sizeof(*shared) ); + mark_block_uninitialized( (void *)shared, shm_size ); CONTAINING_RECORD( shared, shared_object_t, shm )->id = ++session.last_object_id; } SHARED_WRITE_END; @@ -1415,10 +1426,11 @@ volatile void *alloc_shared_object(void) void free_shared_object( volatile void *object_shm ) { struct session_object *object = CONTAINING_RECORD( object_shm, struct session_object, obj.shm ); + mem_size_t shm_size = object->size - sizeof(*object) + sizeof(object_shm_t);
SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) { - mark_block_noaccess( (void *)shared, sizeof(*shared) ); + mark_block_noaccess( (void *)shared, shm_size ); CONTAINING_RECORD( shared, shared_object_t, shm )->id = 0; } SHARED_WRITE_END; diff --git a/server/queue.c b/server/queue.c index 268c921a914..01bff70d702 100644 --- a/server/queue.c +++ b/server/queue.c @@ -263,7 +263,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) memcpy( input->desktop_keystate, (const void *)input->desktop->shared->keystate, sizeof(input->desktop_keystate) );
- if (!(input->shared = alloc_shared_object())) + if (!(input->shared = alloc_shared_object( sizeof(*input->shared) ))) { release_object( input ); return NULL; @@ -325,7 +325,11 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
if (get_inproc_device_fd() >= 0 && !(queue->inproc_sync = create_inproc_internal_sync( 1, 0 ))) goto error; - if (!(queue->shared = alloc_shared_object())) goto error; + if (!(queue->shared = alloc_shared_object( sizeof(*queue->shared) ))) + { + release_object( queue ); + return NULL; + }
SHARED_WRITE_BEGIN( queue->shared, queue_shm_t ) { diff --git a/server/window.c b/server/window.c index 9f871ed9494..d9a2689ae5a 100644 --- a/server/window.c +++ b/server/window.c @@ -681,7 +681,7 @@ static struct window *create_window( struct window *parent, struct window *owner list_init( &win->children ); list_init( &win->unlinked );
- if (!(win->shared = alloc_shared_object())) goto failed; + if (!(win->shared = alloc_shared_object( sizeof(*win->shared) ))) goto failed; SHARED_WRITE_BEGIN( win->shared, window_shm_t ) { shared->class = class_locator; diff --git a/server/winstation.c b/server/winstation.c index bfcd4a53613..52c3f1ce1eb 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -308,7 +308,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned list_init( &desktop->hotkeys ); list_init( &desktop->pointers );
- if (!(desktop->shared = alloc_shared_object())) + if (!(desktop->shared = alloc_shared_object( sizeof(*desktop->shared) ))) { release_object( desktop ); return NULL;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 2 +- server/class.c | 34 +++++++++++++++++----------------- server/protocol.def | 7 +++++-- 3 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 493079908aa..ad031aa86a0 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -554,7 +554,7 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam req->local = class->local; req->style = wc->style; req->instance = wine_server_client_ptr( instance ); - req->extra = class->cbClsExtra; + req->cls_extra = class->cbClsExtra; req->win_extra = wc->cbWndExtra; req->client_ptr = wine_server_client_ptr( class ); req->atom = wine_server_add_atom( req, name ); diff --git a/server/class.c b/server/class.c index a5cd765bc2b..1f223dbecc0 100644 --- a/server/class.c +++ b/server/class.c @@ -49,24 +49,22 @@ struct window_class atom_t atom; /* class atom for versioned class */ client_ptr_t client_ptr; /* pointer to class in client address space */ class_shm_t *shared; /* class in session shared memory */ - int nb_extra_bytes; /* number of extra bytes */ - char extra_bytes[1]; /* extra bytes storage */ };
-static struct window_class *create_class( struct process *process, int extra_bytes, int local, struct unicode_str *name, unsigned int name_offset, - atom_t atom, mod_handle_t instance, unsigned int style, int win_extra ) +C_ASSERT( sizeof(class_shm_t) == offsetof(class_shm_t, extra[0]) ); + +static struct window_class *create_class( struct process *process, int local, struct unicode_str *name, unsigned int name_offset, + atom_t atom, mod_handle_t instance, unsigned int style, int cls_extra, int win_extra ) { struct window_class *class;
- if (!(class = mem_alloc( sizeof(*class) + extra_bytes - 1 ))) return NULL; + if (!(class = mem_alloc( sizeof(*class) ))) return NULL;
class->process = (struct process *)grab_object( process ); class->count = 0; class->local = local; - class->nb_extra_bytes = extra_bytes; - memset( class->extra_bytes, 0, extra_bytes );
- if (!(class->shared = alloc_shared_object( sizeof(*class->shared) ))) goto failed; + if (!(class->shared = alloc_shared_object( offsetof(class_shm_t, extra[cls_extra]) ))) goto failed; SHARED_WRITE_BEGIN( class->shared, class_shm_t ) { memcpy( (void *)shared->name, name->str, name->len ); @@ -76,6 +74,8 @@ static struct window_class *create_class( struct process *process, int extra_byt shared->instance = instance; shared->style = style; shared->win_extra = win_extra; + shared->cls_extra = cls_extra; + memset( (void *)shared->extra, 0, cls_extra ); } SHARED_WRITE_END;
@@ -230,7 +230,7 @@ DECL_HANDLER(create_class) release_atom( table, base_atom ); return; } - if (req->extra < 0 || req->extra > 4096 || req->win_extra < 0 || req->win_extra > 4096) + if (req->cls_extra < 0 || req->cls_extra > 4096 || req->win_extra < 0 || req->win_extra > 4096) { /* don't allow stupid values here */ set_error( STATUS_INVALID_PARAMETER ); @@ -239,8 +239,8 @@ DECL_HANDLER(create_class) return; }
- if (!(class = create_class( current->process, req->extra, req->local, &name, offset, - base_atom, req->instance, req->style, req->win_extra ))) + if (!(class = create_class( current->process, req->local, &name, offset, base_atom, + req->instance, req->style, req->cls_extra, req->win_extra ))) { release_atom( table, atom ); release_atom( table, base_atom ); @@ -313,13 +313,13 @@ DECL_HANDLER(set_class_info) break; default: if (req->size > sizeof(req->new_info) || req->offset < 0 || - req->offset > class->nb_extra_bytes - (int)req->size) + req->offset > class->shared->cls_extra - (int)req->size) { set_win32_error( ERROR_INVALID_INDEX ); return; } - memcpy( &reply->old_info, class->extra_bytes + req->offset, req->size ); - memcpy( class->extra_bytes + req->offset, &req->new_info, req->size ); + memcpy( &reply->old_info, (char *)shared->extra + req->offset, req->size ); + memcpy( (char *)shared->extra + req->offset, &req->new_info, req->size ); break; } } @@ -345,15 +345,15 @@ DECL_HANDLER(get_class_info) /* not supported */ set_win32_error( ERROR_INVALID_HANDLE ); break; - case GCL_CBCLSEXTRA: reply->info = class->nb_extra_bytes; break; + case GCL_CBCLSEXTRA: reply->info = class->shared->cls_extra; break; default: if (req->size > sizeof(reply->info) || req->offset < 0 || - req->offset > class->nb_extra_bytes - (int)req->size) + req->offset > class->shared->cls_extra - (int)req->size) { set_win32_error( ERROR_INVALID_INDEX ); return; } - memcpy( &reply->info, class->extra_bytes + req->offset, req->size ); + memcpy( &reply->info, (char *)class->shared->extra + req->offset, req->size ); break; } } diff --git a/server/protocol.def b/server/protocol.def index 37c5e8be83f..a70696b9c96 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1041,11 +1041,14 @@ typedef volatile struct { atom_t atom; /* class atom */ unsigned int style; /* class style */ + unsigned int cls_extra; /* number of class extra bytes */ unsigned int win_extra; /* number of window extra bytes */ mod_handle_t instance; /* module instance */ data_size_t name_offset; /* offset in WCHAR of the unversioned class name, constant */ data_size_t name_len; /* len in bytes of the class name, constant */ WCHAR name[MAX_ATOM_LEN]; /* class name, constant */ + unsigned short __pad; + char extra[]; /* extra bytes storage */ } class_shm_t;
typedef volatile struct @@ -3248,10 +3251,10 @@ enum caret_state @REQ(create_class) int local; /* is it a local class? */ atom_t atom; /* class atom */ + short int cls_extra; /* number of extra class bytes */ + short int win_extra; /* number of window extra bytes */ unsigned int style; /* class style */ mod_handle_t instance; /* module instance */ - int extra; /* number of extra class bytes */ - int win_extra; /* number of window extra bytes */ client_ptr_t client_ptr; /* pointer to class in client address space */ data_size_t name_offset; /* base class name offset for specified atom */ VARARG(name,unicode_str); /* class name */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 68 +++++++++++++++++---------------------------- server/class.c | 9 +----- 2 files changed, 27 insertions(+), 50 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index ad031aa86a0..ba1f7d650af 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -49,7 +49,6 @@ typedef struct tagCLASS struct list entry; /* Entry in class list */ BOOL local; /* Local class? */ WNDPROC winproc; /* Window procedure */ - INT cbClsExtra; /* Class extra bytes */ struct dce *dce; /* Opaque pointer to class DCE */ HICON hIcon; /* Default icon */ HICON hIconSm; /* Default small icon */ @@ -544,17 +543,16 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam if (wc->cbWndExtra > 40) /* Extra bytes are limited to 40 in Win32 */ WARN("Win extra bytes %d is > 40\n", wc->cbWndExtra );
- if (!(class = calloc( 1, sizeof(CLASS) + wc->cbClsExtra ))) return 0; + if (!(class = calloc( 1, sizeof(*class) ))) return 0;
class->local = !is_builtin && !(wc->style & CS_GLOBALCLASS); - class->cbClsExtra = wc->cbClsExtra;
SERVER_START_REQ( create_class ) { req->local = class->local; req->style = wc->style; req->instance = wine_server_client_ptr( instance ); - req->cls_extra = class->cbClsExtra; + req->cls_extra = wc->cbClsExtra; req->win_extra = wc->cbWndExtra; req->client_ptr = wine_server_client_ptr( class ); req->atom = wine_server_add_atom( req, name ); @@ -668,7 +666,7 @@ ATOM WINAPI NtUserGetClassInfoEx( HINSTANCE instance, UNICODE_STRING *name, WNDC { wc->style = class_shm->style; wc->lpfnWndProc = get_winproc( class->winproc, ansi ); - wc->cbClsExtra = class->cbClsExtra; + wc->cbClsExtra = class_shm->cls_extra; wc->cbWndExtra = class_shm->win_extra; wc->hInstance = (instance == user32_module) ? 0 : instance; wc->hIcon = class->hIcon; @@ -824,16 +822,7 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI
if (!(class = get_class_ptr( hwnd, TRUE ))) return 0;
- if (offset >= 0) - { - if (set_server_info( hwnd, offset, newval, size, &retval )) - { - void *ptr = (char *)(class + 1) + offset; - memcpy( &retval, ptr, size ); - memcpy( ptr, &newval, size ); - } - } - else switch(offset) + switch(offset) { case GCLP_MENUNAME: { @@ -928,7 +917,8 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); break; default: - RtlSetLastWin32Error( ERROR_INVALID_INDEX ); + if (offset >= 0) set_server_info( hwnd, offset, newval, size, &retval ); + else RtlSetLastWin32Error( ERROR_INVALID_INDEX ); break; } release_class_ptr( class ); @@ -964,6 +954,7 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi struct object_lock lock = OBJECT_LOCK_INIT; const class_shm_t *class_shm; ULONG_PTR ret = 0; + BOOL valid = TRUE; NTSTATUS status;
while ((status = get_shared_window_class( hwnd, &lock, &class_shm )) == STATUS_PENDING) @@ -972,8 +963,13 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi { case GCW_ATOM: ret = class_shm->atom; break; case GCL_STYLE: ret = class_shm->style; break; + case GCL_CBCLSEXTRA: ret = class_shm->cls_extra; break; case GCL_CBWNDEXTRA: ret = class_shm->win_extra; break; case GCLP_HMODULE: ret = class_shm->instance; break; + default: + valid = offset >= 0 && offset <= (INT)(class_shm->cls_extra - size); + if (valid) memcpy( &ret, (char *)class_shm->extra + offset, size ); + break; } } if (status) @@ -981,6 +977,12 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); return 0; } + if (!valid) + { + WARN( "Invalid window %p offset %d size %u\n", hwnd, offset, size ); + RtlSetLastWin32Error( ERROR_INVALID_INDEX ); + return 0; + }
return ret; } @@ -992,10 +994,14 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans
switch (offset) { - case GCW_ATOM: - case GCL_STYLE: - case GCL_CBWNDEXTRA: - case GCLP_HMODULE: + case GCLP_HICONSM: + case GCLP_WNDPROC: + case GCLP_HICON: + case GCLP_HCURSOR: + case GCLP_HBRBACKGROUND: + case GCLP_MENUNAME: + break; + default: return get_class_long_shm( hwnd, offset, size, ansi ); }
@@ -1030,25 +1036,6 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans return retvalue; }
- if (offset >= 0) - { - if (offset <= class->cbClsExtra - size) - { - if (size == sizeof(DWORD)) - { - DWORD retdword; - memcpy( &retdword, (char *)(class + 1) + offset, sizeof(DWORD) ); - retvalue = retdword; - } - else - memcpy( &retvalue, (char *)(class + 1) + offset, sizeof(ULONG_PTR) ); - } - else - RtlSetLastWin32Error( ERROR_INVALID_INDEX ); - release_class_ptr( class ); - return retvalue; - } - switch(offset) { case GCLP_HBRBACKGROUND: @@ -1063,9 +1050,6 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans case GCLP_HICONSM: retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->hIconSmIntern); break; - case GCL_CBCLSEXTRA: - retvalue = class->cbClsExtra; - break; case GCLP_WNDPROC: retvalue = (ULONG_PTR)get_winproc( class->winproc, ansi ); break; diff --git a/server/class.c b/server/class.c index 1f223dbecc0..64c789fbf50 100644 --- a/server/class.c +++ b/server/class.c @@ -345,15 +345,8 @@ DECL_HANDLER(get_class_info) /* not supported */ set_win32_error( ERROR_INVALID_HANDLE ); break; - case GCL_CBCLSEXTRA: reply->info = class->shared->cls_extra; break; default: - if (req->size > sizeof(reply->info) || req->offset < 0 || - req->offset > class->shared->cls_extra - (int)req->size) - { - set_win32_error( ERROR_INVALID_INDEX ); - return; - } - memcpy( &reply->info, (char *)class->shared->extra + req->offset, req->size ); + set_win32_error( ERROR_INVALID_INDEX ); break; } }
v2: Rebase and fix the tests.