From 78db8b7950c18c7882f800449029c4b9662c25f0 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Fri, 4 Dec 2015 20:06:24 +0100 Subject: [PATCH] Added patch to fix possible leak of explorer.exe processes and implement proper desktop refcounting. --- README.md | 5 + ...rrect-error-codes-for-NtWriteFile-wh.patch | 24 +- patches/kernel32-Named_Pipe/definition | 1 + patches/patchinstall.sh | 43 +- ...-a-new-alloc_handle-object-callback..patch | 686 ++++++++++++++++++ ...-desktop-handle-count-more-correctly.patch | 253 +++++++ patches/server-Desktop_Refcount/definition | 1 + ...rt-for-TF_REUSE_SOCKET-to-TransmitFi.patch | 32 +- patches/ws2_32-TransmitFile/definition | 1 + staging/changelog | 2 + 10 files changed, 1017 insertions(+), 31 deletions(-) create mode 100644 patches/server-Desktop_Refcount/0001-server-Introduce-a-new-alloc_handle-object-callback..patch create mode 100644 patches/server-Desktop_Refcount/0002-server-Track-desktop-handle-count-more-correctly.patch create mode 100644 patches/server-Desktop_Refcount/definition diff --git a/README.md b/README.md index 338d6b03..d19fa770 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,11 @@ Wine. All those differences are also documented on the Included bug fixes and improvements ----------------------------------- +**Bug fixes and features included in the next upcoming release [1]:** + +* Fix possible leak of explorer.exe processes and implement proper desktop refcounting + + **Bug fixes and features in Wine Staging 1.8-rc2 [270]:** *Note: The following list only contains features and bug fixes which are not diff --git a/patches/kernel32-Named_Pipe/0020-server-Return-correct-error-codes-for-NtWriteFile-wh.patch b/patches/kernel32-Named_Pipe/0020-server-Return-correct-error-codes-for-NtWriteFile-wh.patch index 56f8463b..5ea491dc 100644 --- a/patches/kernel32-Named_Pipe/0020-server-Return-correct-error-codes-for-NtWriteFile-wh.patch +++ b/patches/kernel32-Named_Pipe/0020-server-Return-correct-error-codes-for-NtWriteFile-wh.patch @@ -1,4 +1,4 @@ -From 686c258580f515c706074970599fb5a081bdf06a Mon Sep 17 00:00:00 2001 +From ffd7b942761e5010bdc234f10e5e9721c8d8159b Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 6 Jun 2015 01:21:05 +0200 Subject: server: Return correct error codes for NtWriteFile when pipes are @@ -39,10 +39,10 @@ index 42d1fae..3bb2905 100644 } } diff --git a/server/named_pipe.c b/server/named_pipe.c -index 4bdb4d7..c9c08e5 100644 +index 37f97ed..28816a2 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c -@@ -144,6 +144,7 @@ static const struct object_ops named_pipe_ops = +@@ -145,6 +145,7 @@ static const struct object_ops named_pipe_ops = /* server end functions */ static void pipe_server_dump( struct object *obj, int verbose ); static struct fd *pipe_server_get_fd( struct object *obj ); @@ -50,16 +50,16 @@ index 4bdb4d7..c9c08e5 100644 static void pipe_server_destroy( struct object *obj); static obj_handle_t pipe_server_flush( struct fd *fd, const async_data_t *async, int blocking ); static enum server_fd_type pipe_server_get_fd_type( struct fd *fd ); -@@ -166,7 +167,7 @@ static const struct object_ops pipe_server_ops = - default_set_sd, /* set_sd */ +@@ -168,7 +169,7 @@ static const struct object_ops pipe_server_ops = no_lookup_name, /* lookup_name */ no_open_file, /* open_file */ + no_alloc_handle, /* alloc_handle */ - fd_close_handle, /* close_handle */ + pipe_server_close_handle, /* close_handle */ pipe_server_destroy /* destroy */ }; -@@ -188,6 +189,7 @@ static const struct fd_ops pipe_server_fd_ops = +@@ -190,6 +191,7 @@ static const struct fd_ops pipe_server_fd_ops = static void pipe_client_dump( struct object *obj, int verbose ); static int pipe_client_signaled( struct object *obj, struct wait_queue_entry *entry ); static struct fd *pipe_client_get_fd( struct object *obj ); @@ -67,16 +67,16 @@ index 4bdb4d7..c9c08e5 100644 static void pipe_client_destroy( struct object *obj ); static obj_handle_t pipe_client_flush( struct fd *fd, const async_data_t *async, int blocking ); static enum server_fd_type pipe_client_get_fd_type( struct fd *fd ); -@@ -208,7 +210,7 @@ static const struct object_ops pipe_client_ops = - default_set_sd, /* set_sd */ +@@ -211,7 +213,7 @@ static const struct object_ops pipe_client_ops = no_lookup_name, /* lookup_name */ no_open_file, /* open_file */ + no_alloc_handle, /* alloc_handle */ - fd_close_handle, /* close_handle */ + pipe_client_close_handle, /* close_handle */ pipe_client_destroy /* destroy */ }; -@@ -272,6 +274,8 @@ static const struct fd_ops named_pipe_device_fd_ops = +@@ -276,6 +278,8 @@ static const struct fd_ops named_pipe_device_fd_ops = default_fd_cancel_async /* cancel_async */ }; @@ -85,7 +85,7 @@ index 4bdb4d7..c9c08e5 100644 static void named_pipe_dump( struct object *obj, int verbose ) { struct named_pipe *pipe = (struct named_pipe *) obj; -@@ -386,6 +390,23 @@ static void do_disconnect( struct pipe_server *server ) +@@ -390,6 +394,23 @@ static void do_disconnect( struct pipe_server *server ) server->fd = NULL; } @@ -109,7 +109,7 @@ index 4bdb4d7..c9c08e5 100644 static void pipe_server_destroy( struct object *obj) { struct pipe_server *server = (struct pipe_server *)obj; -@@ -412,6 +433,24 @@ static void pipe_server_destroy( struct object *obj) +@@ -416,6 +437,24 @@ static void pipe_server_destroy( struct object *obj) release_object( server->pipe ); } @@ -135,7 +135,7 @@ index 4bdb4d7..c9c08e5 100644 { struct pipe_client *client = (struct pipe_client *)obj; diff --git a/server/protocol.def b/server/protocol.def -index d0a949f..91ab8cc 100644 +index 6b2030b..390c09a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2389,6 +2389,7 @@ enum message_type diff --git a/patches/kernel32-Named_Pipe/definition b/patches/kernel32-Named_Pipe/definition index 39b4733d..8b67f93f 100644 --- a/patches/kernel32-Named_Pipe/definition +++ b/patches/kernel32-Named_Pipe/definition @@ -4,4 +4,5 @@ Fixes: Improve ReadDataAvailable handling in FilePipeLocalInformation class Fixes: Set NamedPipeState to FILE_PIPE_CLOSING_STATE on broken pipe in NtQueryInformationFile FIxes: Return proper status codes when NtReadFile/NtWriteFile is called on closed (but not disconnected) pipe Depends: rpcrt4-Pipe_Transport +Depends: server-Desktop_Refcount Category: stable diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index fca3306c..1211e646 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -236,6 +236,7 @@ patch_enable_all () enable_secur32_ANSI_NTLM_Credentials="$1" enable_server_ClipCursor="$1" enable_server_CreateProcess_ACLs="$1" + enable_server_Desktop_Refcount="$1" enable_server_FileEndOfFileInformation="$1" enable_server_File_Permissions="$1" enable_server_Inherited_ACLs="$1" @@ -818,6 +819,9 @@ patch_enable () server-CreateProcess_ACLs) enable_server_CreateProcess_ACLs="$2" ;; + server-Desktop_Refcount) + enable_server_Desktop_Refcount="$2" + ;; server-FileEndOfFileInformation) enable_server_FileEndOfFileInformation="$2" ;; @@ -1755,6 +1759,13 @@ if test "$enable_category_stable" -eq 1; then enable_ws2_32_WriteWatches=1 fi +if test "$enable_ws2_32_TransmitFile" -eq 1; then + if test "$enable_server_Desktop_Refcount" -gt 1; then + abort "Patchset server-Desktop_Refcount disabled, but ws2_32-TransmitFile depends on that." + fi + enable_server_Desktop_Refcount=1 +fi + if test "$enable_wined3d_CSMT_Main" -eq 1; then if test "$enable_wined3d_CSMT_Helper" -gt 1; then abort "Patchset wined3d-CSMT_Helper disabled, but wined3d-CSMT_Main depends on that." @@ -1961,7 +1972,11 @@ if test "$enable_kernel32_Named_Pipe" -eq 1; then if test "$enable_rpcrt4_Pipe_Transport" -gt 1; then abort "Patchset rpcrt4-Pipe_Transport disabled, but kernel32-Named_Pipe depends on that." fi + if test "$enable_server_Desktop_Refcount" -gt 1; then + abort "Patchset server-Desktop_Refcount disabled, but kernel32-Named_Pipe depends on that." + fi enable_rpcrt4_Pipe_Transport=1 + enable_server_Desktop_Refcount=1 fi if test "$enable_kernel32_CopyFileEx" -eq 1; then @@ -3518,10 +3533,29 @@ if test "$enable_rpcrt4_Pipe_Transport" -eq 1; then ) >> "$patchlist" fi +# Patchset server-Desktop_Refcount +# | +# | Modified files: +# | * programs/explorer/desktop.c, server/async.c, server/atom.c, server/change.c, server/clipboard.c, server/completion.c, +# | server/console.c, server/debugger.c, server/device.c, server/directory.c, server/event.c, server/fd.c, server/file.c, +# | server/handle.c, server/handle.h, server/hook.c, server/mailslot.c, server/mapping.c, server/mutex.c, +# | server/named_pipe.c, server/object.c, server/object.h, server/process.c, server/queue.c, server/registry.c, +# | server/request.c, server/semaphore.c, server/serial.c, server/signal.c, server/snapshot.c, server/sock.c, +# | server/symlink.c, server/thread.c, server/timer.c, server/token.c, server/winstation.c +# | +if test "$enable_server_Desktop_Refcount" -eq 1; then + patch_apply server-Desktop_Refcount/0001-server-Introduce-a-new-alloc_handle-object-callback..patch + patch_apply server-Desktop_Refcount/0002-server-Track-desktop-handle-count-more-correctly.patch + ( + echo '+ { "Sebastian Lackner", "server: Introduce a new alloc_handle object callback.", 2 },'; + echo '+ { "Sebastian Lackner", "server: Track desktop handle count more correctly.", 1 },'; + ) >> "$patchlist" +fi + # Patchset kernel32-Named_Pipe # | # | This patchset has the following (direct or indirect) dependencies: -# | * rpcrt4-Pipe_Transport +# | * rpcrt4-Pipe_Transport, server-Desktop_Refcount # | # | This patchset fixes the following Wine bugs: # | * [#16550] Fix for ConnectNamedPort return value in overlapped mode @@ -4438,7 +4472,7 @@ fi # Patchset ntdll-WriteWatches # | # | This patchset has the following (direct or indirect) dependencies: -# | * rpcrt4-Pipe_Transport, kernel32-Named_Pipe, ws2_32-WriteWatches +# | * rpcrt4-Pipe_Transport, server-Desktop_Refcount, kernel32-Named_Pipe, ws2_32-WriteWatches # | # | Modified files: # | * dlls/kernel32/tests/virtual.c, dlls/ntdll/file.c @@ -4937,7 +4971,7 @@ fi # Patchset server-Pipe_ObjectName # | # | This patchset has the following (direct or indirect) dependencies: -# | * rpcrt4-Pipe_Transport, kernel32-Named_Pipe +# | * rpcrt4-Pipe_Transport, server-Desktop_Refcount, kernel32-Named_Pipe # | # | Modified files: # | * server/named_pipe.c, server/object.c, server/object.h @@ -6625,6 +6659,9 @@ fi # Patchset ws2_32-TransmitFile # | +# | This patchset has the following (direct or indirect) dependencies: +# | * server-Desktop_Refcount +# | # | Modified files: # | * dlls/ws2_32/socket.c, dlls/ws2_32/tests/sock.c, include/winsock.h, server/protocol.def, server/sock.c # | diff --git a/patches/server-Desktop_Refcount/0001-server-Introduce-a-new-alloc_handle-object-callback..patch b/patches/server-Desktop_Refcount/0001-server-Introduce-a-new-alloc_handle-object-callback..patch new file mode 100644 index 00000000..5860b61f --- /dev/null +++ b/patches/server-Desktop_Refcount/0001-server-Introduce-a-new-alloc_handle-object-callback..patch @@ -0,0 +1,686 @@ +From a04ff4bba9832fd787972911fb391558f129870c Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Fri, 4 Dec 2015 10:36:47 +0100 +Subject: server: Introduce a new alloc_handle object callback. (v2) + +Signed-off-by: Sebastian Lackner +--- + server/async.c | 2 ++ + server/atom.c | 1 + + server/change.c | 1 + + server/clipboard.c | 1 + + server/completion.c | 1 + + server/console.c | 3 +++ + server/debugger.c | 2 ++ + server/device.c | 4 ++++ + server/directory.c | 2 ++ + server/event.c | 2 ++ + server/fd.c | 4 ++++ + server/file.c | 1 + + server/handle.c | 13 +++++++++++-- + server/hook.c | 1 + + server/mailslot.c | 3 +++ + server/mapping.c | 1 + + server/mutex.c | 1 + + server/named_pipe.c | 4 ++++ + server/object.c | 4 ++++ + server/object.h | 5 ++++- + server/process.c | 3 +++ + server/queue.c | 2 ++ + server/registry.c | 1 + + server/request.c | 1 + + server/semaphore.c | 1 + + server/serial.c | 1 + + server/signal.c | 1 + + server/snapshot.c | 1 + + server/sock.c | 2 ++ + server/symlink.c | 1 + + server/thread.c | 2 ++ + server/timer.c | 1 + + server/token.c | 1 + + server/winstation.c | 2 ++ + 34 files changed, 73 insertions(+), 3 deletions(-) + +diff --git a/server/async.c b/server/async.c +index d2da976..b00d2cc 100644 +--- a/server/async.c ++++ b/server/async.c +@@ -66,6 +66,7 @@ static const struct object_ops async_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + async_destroy /* destroy */ + }; +@@ -99,6 +100,7 @@ static const struct object_ops async_queue_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + async_queue_destroy /* destroy */ + }; +diff --git a/server/atom.c b/server/atom.c +index 0ed4ed5..1f694bc 100644 +--- a/server/atom.c ++++ b/server/atom.c +@@ -88,6 +88,7 @@ static const struct object_ops atom_table_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + atom_table_destroy /* destroy */ + }; +diff --git a/server/change.c b/server/change.c +index 59d1819..4f36179 100644 +--- a/server/change.c ++++ b/server/change.c +@@ -167,6 +167,7 @@ static const struct object_ops dir_ops = + dir_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + dir_destroy /* destroy */ + }; +diff --git a/server/clipboard.c b/server/clipboard.c +index 2f56c72..1f988bc 100644 +--- a/server/clipboard.c ++++ b/server/clipboard.c +@@ -66,6 +66,7 @@ static const struct object_ops clipboard_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +diff --git a/server/completion.c b/server/completion.c +index 77c72cc..97d2102 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -73,6 +73,7 @@ static const struct object_ops completion_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + completion_destroy /* destroy */ + }; +diff --git a/server/console.c b/server/console.c +index a57b2fe..264b45f 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -85,6 +85,7 @@ static const struct object_ops console_input_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + console_input_destroy /* destroy */ + }; +@@ -117,6 +118,7 @@ static const struct object_ops console_input_events_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + console_input_events_destroy /* destroy */ + }; +@@ -169,6 +171,7 @@ static const struct object_ops screen_buffer_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + screen_buffer_destroy /* destroy */ + }; +diff --git a/server/debugger.c b/server/debugger.c +index 374f2ad..5e9e6bf 100644 +--- a/server/debugger.c ++++ b/server/debugger.c +@@ -82,6 +82,7 @@ static const struct object_ops debug_event_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + debug_event_destroy /* destroy */ + }; +@@ -106,6 +107,7 @@ static const struct object_ops debug_ctx_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + debug_ctx_destroy /* destroy */ + }; +diff --git a/server/device.c b/server/device.c +index fb91c02..e207ba8 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -79,6 +79,7 @@ static const struct object_ops irp_call_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + irp_call_destroy /* destroy */ + }; +@@ -113,6 +114,7 @@ static const struct object_ops device_manager_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + device_manager_destroy /* destroy */ + }; +@@ -152,6 +154,7 @@ static const struct object_ops device_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + device_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + device_destroy /* destroy */ + }; +@@ -198,6 +201,7 @@ static const struct object_ops device_file_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + device_file_close_handle, /* close_handle */ + device_file_destroy /* destroy */ + }; +diff --git a/server/directory.c b/server/directory.c +index e0cf75e..da98fb0 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -65,6 +65,7 @@ static const struct object_ops object_type_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +@@ -98,6 +99,7 @@ static const struct object_ops directory_ops = + default_set_sd, /* set_sd */ + directory_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + directory_destroy /* destroy */ + }; +diff --git a/server/event.c b/server/event.c +index 4d3c562..9c09694 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -66,6 +66,7 @@ static const struct object_ops event_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +@@ -97,6 +98,7 @@ static const struct object_ops keyed_event_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +diff --git a/server/fd.c b/server/fd.c +index e3fe292..3e6373a 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -210,6 +210,7 @@ static const struct object_ops fd_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + fd_destroy /* destroy */ + }; +@@ -247,6 +248,7 @@ static const struct object_ops device_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + device_destroy /* destroy */ + }; +@@ -283,6 +285,7 @@ static const struct object_ops inode_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + inode_destroy /* destroy */ + }; +@@ -321,6 +324,7 @@ static const struct object_ops file_lock_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +diff --git a/server/file.c b/server/file.c +index a07ca16..c9c47a4 100644 +--- a/server/file.c ++++ b/server/file.c +@@ -92,6 +92,7 @@ static const struct object_ops file_ops = + file_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + file_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + file_destroy /* destroy */ + }; +diff --git a/server/handle.c b/server/handle.c +index 5043ff7..64db8fc 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -131,6 +131,7 @@ static const struct object_ops handle_table_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + handle_table_destroy /* destroy */ + }; +@@ -229,7 +230,7 @@ static int grow_handle_table( struct handle_table *table ) + } + + /* allocate the first free entry in the handle table */ +-static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned int access ) ++static obj_handle_t alloc_entry( struct handle_table *table, struct object *obj, unsigned int access ) + { + struct handle_entry *entry = table->entries + table->free; + int i; +@@ -245,6 +246,10 @@ static obj_handle_t alloc_entry( struct handle_table *table, void *obj, unsigned + table->free = i + 1; + entry->ptr = grab_object_for_handle( obj ); + entry->access = access; ++ ++ if (table->process) ++ obj->ops->alloc_handle( obj, table->process, index_to_handle(i) ); ++ + return index_to_handle(i); + } + +@@ -369,7 +374,11 @@ struct handle_table *copy_handle_table( struct process *process, struct process + for (i = 0; i <= table->last; i++, ptr++) + { + if (!ptr->ptr) continue; +- if (ptr->access & RESERVED_INHERIT) grab_object_for_handle( ptr->ptr ); ++ if (ptr->access & RESERVED_INHERIT) ++ { ++ ptr->ptr->ops->alloc_handle( ptr->ptr, process, index_to_handle(i) ); ++ grab_object_for_handle( ptr->ptr ); ++ } + else ptr->ptr = NULL; /* don't inherit this entry */ + } + } +diff --git a/server/hook.c b/server/hook.c +index a8e6ab9..c005cae 100644 +--- a/server/hook.c ++++ b/server/hook.c +@@ -89,6 +89,7 @@ static const struct object_ops hook_table_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + hook_table_destroy /* destroy */ + }; +diff --git a/server/mailslot.c b/server/mailslot.c +index 97ea3f6..5075a1a 100644 +--- a/server/mailslot.c ++++ b/server/mailslot.c +@@ -86,6 +86,7 @@ static const struct object_ops mailslot_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + mailslot_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + mailslot_destroy /* destroy */ + }; +@@ -139,6 +140,7 @@ static const struct object_ops mail_writer_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + mail_writer_destroy /* destroy */ + }; +@@ -193,6 +195,7 @@ static const struct object_ops mailslot_device_ops = + default_set_sd, /* set_sd */ + mailslot_device_lookup_name, /* lookup_name */ + mailslot_device_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + mailslot_device_destroy /* destroy */ + }; +diff --git a/server/mapping.c b/server/mapping.c +index 16e7c1c..fd31df2 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -92,6 +92,7 @@ static const struct object_ops mapping_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + mapping_destroy /* destroy */ + }; +diff --git a/server/mutex.c b/server/mutex.c +index 910fbca..6e23770 100644 +--- a/server/mutex.c ++++ b/server/mutex.c +@@ -69,6 +69,7 @@ static const struct object_ops mutex_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + mutex_destroy /* destroy */ + }; +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 8d5753a..f48ead9 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -132,6 +132,7 @@ static const struct object_ops named_pipe_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + named_pipe_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + named_pipe_destroy /* destroy */ + }; +@@ -161,6 +162,7 @@ static const struct object_ops pipe_server_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + pipe_server_destroy /* destroy */ + }; +@@ -203,6 +205,7 @@ static const struct object_ops pipe_client_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + pipe_client_destroy /* destroy */ + }; +@@ -249,6 +252,7 @@ static const struct object_ops named_pipe_device_ops = + default_set_sd, /* set_sd */ + named_pipe_device_lookup_name, /* lookup_name */ + named_pipe_device_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + named_pipe_device_destroy /* destroy */ + }; +diff --git a/server/object.c b/server/object.c +index 31883bd..3ccaa4c 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -548,6 +548,10 @@ struct object *no_open_file( struct object *obj, unsigned int access, unsigned i + return NULL; + } + ++void no_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle ) ++{ ++} ++ + int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) + { + return 1; /* ok to close */ +diff --git a/server/object.h b/server/object.h +index b59811f..06ee321 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -86,8 +86,10 @@ struct object_ops + /* open a file object to access this object */ + struct object *(*open_file)(struct object *, unsigned int access, unsigned int sharing, + unsigned int options); ++ /* allocate a handle to this object */ ++ void (*alloc_handle)(struct object *, struct process *, obj_handle_t); + /* close a handle to this object */ +- int (*close_handle)(struct object *,struct process *,obj_handle_t); ++ int (*close_handle)(struct object *, struct process *, obj_handle_t); + /* destroy on refcount == 0 */ + void (*destroy)(struct object *); + }; +@@ -145,6 +147,7 @@ extern int set_sd_defaults_from_token( struct object *obj, const struct security + extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name, unsigned int attributes ); + extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing, + unsigned int options ); ++extern void no_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle ); + extern int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); + extern void no_destroy( struct object *obj ); + #ifdef DEBUG_OBJECTS +diff --git a/server/process.c b/server/process.c +index e00b429..bc86c24 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -82,6 +82,7 @@ static const struct object_ops process_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + process_destroy /* destroy */ + }; +@@ -130,6 +131,7 @@ static const struct object_ops startup_info_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + startup_info_destroy /* destroy */ + }; +@@ -171,6 +173,7 @@ static const struct object_ops job_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + job_close_handle, /* close_handle */ + job_destroy /* destroy */ + }; +diff --git a/server/queue.c b/server/queue.c +index 3099e12..bdc740d 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -179,6 +179,7 @@ static const struct object_ops msg_queue_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + msg_queue_destroy /* destroy */ + }; +@@ -212,6 +213,7 @@ static const struct object_ops thread_input_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + thread_input_destroy /* destroy */ + }; +diff --git a/server/registry.c b/server/registry.c +index a3c1390..2db56c3 100644 +--- a/server/registry.c ++++ b/server/registry.c +@@ -167,6 +167,7 @@ static const struct object_ops key_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + key_close_handle, /* close_handle */ + key_destroy /* destroy */ + }; +diff --git a/server/request.c b/server/request.c +index f78026a..bd01179 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -103,6 +103,7 @@ static const struct object_ops master_socket_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + master_socket_destroy /* destroy */ + }; +diff --git a/server/semaphore.c b/server/semaphore.c +index d87325c..aaf2d65 100644 +--- a/server/semaphore.c ++++ b/server/semaphore.c +@@ -66,6 +66,7 @@ static const struct object_ops semaphore_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +diff --git a/server/serial.c b/server/serial.c +index 164a4b1..cc9c3bc 100644 +--- a/server/serial.c ++++ b/server/serial.c +@@ -101,6 +101,7 @@ static const struct object_ops serial_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + serial_destroy /* destroy */ + }; +diff --git a/server/signal.c b/server/signal.c +index 5e4fe33..308f494 100644 +--- a/server/signal.c ++++ b/server/signal.c +@@ -75,6 +75,7 @@ static const struct object_ops handler_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + handler_destroy /* destroy */ + }; +diff --git a/server/snapshot.c b/server/snapshot.c +index dd00bd1..b827c6f 100644 +--- a/server/snapshot.c ++++ b/server/snapshot.c +@@ -69,6 +69,7 @@ static const struct object_ops snapshot_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + snapshot_destroy /* destroy */ + }; +diff --git a/server/sock.c b/server/sock.c +index 1767dea..57d3d93 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -154,6 +154,7 @@ static const struct object_ops sock_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + fd_close_handle, /* close_handle */ + sock_destroy /* destroy */ + }; +@@ -996,6 +997,7 @@ static const struct object_ops ifchange_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + ifchange_destroy /* destroy */ + }; +diff --git a/server/symlink.c b/server/symlink.c +index 2330fde..1107639 100644 +--- a/server/symlink.c ++++ b/server/symlink.c +@@ -68,6 +68,7 @@ static const struct object_ops symlink_ops = + default_set_sd, /* set_sd */ + symlink_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + symlink_destroy /* destroy */ + }; +diff --git a/server/thread.c b/server/thread.c +index bad2231..9407938 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -118,6 +118,7 @@ static const struct object_ops thread_apc_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + thread_apc_destroy /* destroy */ + }; +@@ -147,6 +148,7 @@ static const struct object_ops thread_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + destroy_thread /* destroy */ + }; +diff --git a/server/timer.c b/server/timer.c +index 9c293f2..9957ee3 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -73,6 +73,7 @@ static const struct object_ops timer_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + timer_destroy /* destroy */ + }; +diff --git a/server/token.c b/server/token.c +index 42cfb3d..893d58f 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -159,6 +159,7 @@ static const struct object_ops token_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + no_close_handle, /* close_handle */ + token_destroy /* destroy */ + }; +diff --git a/server/winstation.c b/server/winstation.c +index 5016184..c4e55e3 100644 +--- a/server/winstation.c ++++ b/server/winstation.c +@@ -71,6 +71,7 @@ static const struct object_ops winstation_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + winstation_close_handle, /* close_handle */ + winstation_destroy /* destroy */ + }; +@@ -92,6 +93,7 @@ static const struct object_ops desktop_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ ++ no_alloc_handle, /* alloc_handle */ + desktop_close_handle, /* close_handle */ + desktop_destroy /* destroy */ + }; +-- +2.6.2 + diff --git a/patches/server-Desktop_Refcount/0002-server-Track-desktop-handle-count-more-correctly.patch b/patches/server-Desktop_Refcount/0002-server-Track-desktop-handle-count-more-correctly.patch new file mode 100644 index 00000000..670fb80e --- /dev/null +++ b/patches/server-Desktop_Refcount/0002-server-Track-desktop-handle-count-more-correctly.patch @@ -0,0 +1,253 @@ +From dd59d5fa25b8a20842e565d656c2b0f7833dae6c Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Fri, 4 Dec 2015 01:22:29 +0100 +Subject: server: Track desktop handle count more correctly. + +Desktop objects should stay valid, as long as there is a handle from a +(non-system) process. Counting only process->desktop references is not +sufficient in practice, and causes explorer.exe process leaks. + +Signed-off-by: Sebastian Lackner +--- + programs/explorer/desktop.c | 18 +++++++++- + server/handle.c | 3 +- + server/handle.h | 2 +- + server/process.c | 1 - + server/winstation.c | 88 +++++++++++++++++++++++---------------------- + 5 files changed, 65 insertions(+), 47 deletions(-) + +diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c +index 2b8502b..b59ed4e 100644 +--- a/programs/explorer/desktop.c ++++ b/programs/explorer/desktop.c +@@ -37,6 +37,8 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(explorer); + ++extern HANDLE CDECL __wine_make_process_system(void); ++ + #define DESKTOP_CLASS_ATOM ((LPCWSTR)MAKEINTATOM(32769)) + #define DESKTOP_ALL_ACCESS 0x01ff + +@@ -1024,8 +1026,22 @@ void manage_desktop( WCHAR *arg ) + /* run the desktop message loop */ + if (hwnd) + { ++ HANDLE exit_event = __wine_make_process_system(); + WINE_TRACE( "desktop message loop starting on hwnd %p\n", hwnd ); +- while (GetMessageW( &msg, 0, 0, 0 )) DispatchMessageW( &msg ); ++ while (exit_event != NULL && MsgWaitForMultipleObjectsEx( 1, ++ &exit_event, INFINITE, QS_ALLINPUT, 0 ) == WAIT_OBJECT_0 + 1) ++ { ++ while (PeekMessageW( &msg, NULL, 0, 0, PM_REMOVE )) ++ { ++ if (msg.message == WM_QUIT) ++ { ++ exit_event = NULL; ++ break; ++ } ++ TranslateMessage( &msg ); ++ DispatchMessageW( &msg ); ++ } ++ } + WINE_TRACE( "desktop message loop exiting for hwnd %p\n", hwnd ); + } + +diff --git a/server/handle.c b/server/handle.c +index 64db8fc..63dbf4e 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -487,7 +487,7 @@ obj_handle_t find_inherited_handle( struct process *process, const struct object + /* enumerate handles of a given type */ + /* this is needed for window stations and desktops */ + obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops, +- unsigned int *index ) ++ obj_handle_t *index, struct object **obj ) + { + struct handle_table *table = process->handles; + unsigned int i; +@@ -500,6 +500,7 @@ obj_handle_t enumerate_handles( struct process *process, const struct object_ops + if (!entry->ptr) continue; + if (entry->ptr->ops != ops) continue; + *index = i + 1; ++ if (obj) *obj = grab_object( entry->ptr ); + return index_to_handle(i); + } + return 0; +diff --git a/server/handle.h b/server/handle.h +index 821c4ef..583a25a 100644 +--- a/server/handle.h ++++ b/server/handle.h +@@ -48,7 +48,7 @@ extern obj_handle_t open_object( const struct namespace *namespace, const struct + const struct object_ops *ops, unsigned int access, unsigned int attr ); + extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops ); + extern obj_handle_t enumerate_handles( struct process *process, const struct object_ops *ops, +- unsigned int *index ); ++ unsigned int *index, struct object **obj ); + extern void close_process_handles( struct process *process ); + extern struct handle_table *alloc_handle_table( struct process *process, int count ); + extern struct handle_table *copy_handle_table( struct process *process, struct process *parent ); +diff --git a/server/process.c b/server/process.c +index bc86c24..77771e5 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -832,7 +832,6 @@ static void process_killed( struct process *process ) + + assert( list_empty( &process->thread_list )); + process->end_time = current_time; +- if (!process->is_system) close_process_desktop( process ); + process->winstation = 0; + process->desktop = 0; + close_process_handles( process ); +diff --git a/server/winstation.c b/server/winstation.c +index c4e55e3..78bd24c 100644 +--- a/server/winstation.c ++++ b/server/winstation.c +@@ -51,6 +51,7 @@ static void winstation_destroy( struct object *obj ); + static unsigned int winstation_map_access( struct object *obj, unsigned int access ); + static void desktop_dump( struct object *obj, int verbose ); + static struct object_type *desktop_get_type( struct object *obj ); ++static void desktop_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle ); + static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); + static void desktop_destroy( struct object *obj ); + static unsigned int desktop_map_access( struct object *obj, unsigned int access ); +@@ -93,7 +94,7 @@ static const struct object_ops desktop_ops = + default_set_sd, /* set_sd */ + no_lookup_name, /* lookup_name */ + no_open_file, /* open_file */ +- no_alloc_handle, /* alloc_handle */ ++ desktop_alloc_handle, /* alloc_handle */ + desktop_close_handle, /* close_handle */ + desktop_destroy /* destroy */ + }; +@@ -261,14 +262,54 @@ static struct object_type *desktop_get_type( struct object *obj ) + return get_object_type( &str ); + } + ++static void close_desktop_timeout( void *private ) ++{ ++ struct desktop *desktop = private; ++ ++ desktop->close_timeout = NULL; ++ unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ ++ post_desktop_message( desktop, WM_CLOSE, 0, 0 ); /* and signal the owner to quit */ ++} ++ ++/* remove a user of the desktop and start the close timeout if necessary */ ++static void remove_desktop_user( struct desktop *desktop ) ++{ ++ assert( desktop->users > 0 ); ++ desktop->users--; ++ ++ if (!desktop->users && get_top_window_owner( desktop )) ++ { ++ assert( !desktop->close_timeout ); ++ desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); ++ } ++} ++ ++static void desktop_alloc_handle( struct object *obj, struct process *process, obj_handle_t handle ) ++{ ++ struct desktop *desktop = (struct desktop *)obj; ++ if (process->is_system) return; ++ ++ desktop->users++; ++ if (desktop->close_timeout) ++ { ++ remove_timeout_user( desktop->close_timeout ); ++ desktop->close_timeout = NULL; ++ } ++} ++ + static int desktop_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) + { ++ struct desktop *desktop = (struct desktop *)obj; + struct thread *thread; + + /* check if the handle is currently used by the process or one of its threads */ + if (process->desktop == handle) return 0; + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + if (thread->desktop == handle) return 0; ++ ++ if (!process->is_system) ++ remove_desktop_user( desktop ); ++ + return 1; + } + +@@ -276,6 +317,7 @@ static void desktop_destroy( struct object *obj ) + { + struct desktop *desktop = (struct desktop *)obj; + ++ assert( !desktop->users ); + free_hotkeys( desktop, 0 ); + if (desktop->top_window) destroy_window( desktop->top_window ); + if (desktop->msg_window) destroy_window( desktop->msg_window ); +@@ -302,40 +344,6 @@ struct desktop *get_thread_desktop( struct thread *thread, unsigned int access ) + return get_desktop_obj( thread->process, thread->desktop, access ); + } + +-static void close_desktop_timeout( void *private ) +-{ +- struct desktop *desktop = private; +- +- desktop->close_timeout = NULL; +- unlink_named_object( &desktop->obj ); /* make sure no other process can open it */ +- post_desktop_message( desktop, WM_CLOSE, 0, 0 ); /* and signal the owner to quit */ +-} +- +-/* add a user of the desktop and cancel the close timeout */ +-static void add_desktop_user( struct desktop *desktop ) +-{ +- desktop->users++; +- if (desktop->close_timeout) +- { +- remove_timeout_user( desktop->close_timeout ); +- desktop->close_timeout = NULL; +- } +-} +- +-/* remove a user of the desktop and start the close timeout if necessary */ +-static void remove_desktop_user( struct desktop *desktop ) +-{ +- assert( desktop->users > 0 ); +- desktop->users--; +- +- /* if we have one remaining user, it has to be the manager of the desktop window */ +- if (desktop->users == 1 && get_top_window_owner( desktop )) +- { +- assert( !desktop->close_timeout ); +- desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); +- } +-} +- + /* set the process default desktop handle */ + void set_process_default_desktop( struct process *process, struct desktop *desktop, + obj_handle_t handle ) +@@ -352,12 +360,6 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + if (!thread->desktop) thread->desktop = handle; + +- if (!process->is_system && desktop != old_desktop) +- { +- add_desktop_user( desktop ); +- if (old_desktop) remove_desktop_user( old_desktop ); +- } +- + if (old_desktop) release_object( old_desktop ); + } + +@@ -407,8 +409,8 @@ done: + void close_process_desktop( struct process *process ) + { + struct desktop *desktop; +- +- if (process->desktop && (desktop = get_desktop_obj( process, process->desktop, 0 ))) ++ unsigned int i = 0; ++ while (enumerate_handles( process, &desktop_ops, &i, (struct object **)&desktop )) + { + remove_desktop_user( desktop ); + release_object( desktop ); +-- +2.6.2 + diff --git a/patches/server-Desktop_Refcount/definition b/patches/server-Desktop_Refcount/definition new file mode 100644 index 00000000..807019b3 --- /dev/null +++ b/patches/server-Desktop_Refcount/definition @@ -0,0 +1 @@ +Fixes: Fix possible leak of explorer.exe processes and implement proper desktop refcounting diff --git a/patches/ws2_32-TransmitFile/0002-ws2_32-Add-support-for-TF_REUSE_SOCKET-to-TransmitFi.patch b/patches/ws2_32-TransmitFile/0002-ws2_32-Add-support-for-TF_REUSE_SOCKET-to-TransmitFi.patch index d375dbca..b0da9501 100644 --- a/patches/ws2_32-TransmitFile/0002-ws2_32-Add-support-for-TF_REUSE_SOCKET-to-TransmitFi.patch +++ b/patches/ws2_32-TransmitFile/0002-ws2_32-Add-support-for-TF_REUSE_SOCKET-to-TransmitFi.patch @@ -1,4 +1,4 @@ -From 58723ec84900590ae95a7abd688540d963372993 Mon Sep 17 00:00:00 2001 +From 361a906c0026d132a08bc292450a098fd2fc072b Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Thu, 16 Jan 2014 19:08:30 -0700 Subject: ws2_32: Add support for TF_REUSE_SOCKET to TransmitFile. @@ -12,10 +12,10 @@ Subject: ws2_32: Add support for TF_REUSE_SOCKET to TransmitFile. 5 files changed, 75 insertions(+), 11 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c -index 7deaeda..258f121 100644 +index 9cff400..c2dbbf4 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c -@@ -2886,6 +2886,17 @@ static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *ws +@@ -2888,6 +2888,17 @@ static NTSTATUS WS2_transmitfile_base( int fd, struct ws2_transmitfile_async *ws if (status != STATUS_SUCCESS) return status; @@ -33,7 +33,7 @@ index 7deaeda..258f121 100644 if (wsa->flags & TF_DISCONNECT) { /* we can't use WS_closesocket because it modifies the last error */ -@@ -2929,7 +2940,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD +@@ -2931,7 +2942,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD file_bytes, DWORD LPOVERLAPPED overlapped, LPTRANSMIT_FILE_BUFFERS buffers, DWORD flags ) { @@ -43,10 +43,10 @@ index 7deaeda..258f121 100644 unsigned int uaddrlen = sizeof(uaddr); struct ws2_transmitfile_async *wsa; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c -index d5c206c..4e1a432 100644 +index 41554b4..9462628 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c -@@ -7675,7 +7675,6 @@ static void test_TransmitFile(void) +@@ -8049,7 +8049,6 @@ static void test_TransmitFile(void) err, WSAENOTSOCK); /* Test TransmitFile with a UDP datagram socket */ @@ -55,10 +55,10 @@ index d5c206c..4e1a432 100644 bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); err = WSAGetLastError(); diff --git a/include/winsock.h b/include/winsock.h -index 50237e8..e53aa1e 100644 +index cf9adf5..2feb224 100644 --- a/include/winsock.h +++ b/include/winsock.h -@@ -814,6 +814,7 @@ typedef struct WS(WSAData) +@@ -816,6 +816,7 @@ typedef struct WS(WSAData) /* internal per-socket flags */ #ifdef __WINESRC__ @@ -67,7 +67,7 @@ index 50237e8..e53aa1e 100644 #define FD_WINE_NONBLOCKING 0x20000000 #define FD_WINE_CONNECTED 0x40000000 diff --git a/server/protocol.def b/server/protocol.def -index c313006..5588f6a 100644 +index 04814c9..8a2d395 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1263,6 +1263,12 @@ enum server_fd_type @@ -84,7 +84,7 @@ index c313006..5588f6a 100644 @REQ(set_socket_event) obj_handle_t handle; /* handle to the socket */ diff --git a/server/sock.c b/server/sock.c -index 1767dea..0f029bf 100644 +index 57d3d93..37c78b1 100644 --- a/server/sock.c +++ b/server/sock.c @@ -86,6 +86,7 @@ @@ -103,16 +103,16 @@ index 1767dea..0f029bf 100644 static int sock_get_ntstatus( int err ); static int sock_get_error( int err ); -@@ -154,7 +156,7 @@ static const struct object_ops sock_ops = - default_set_sd, /* set_sd */ +@@ -155,7 +157,7 @@ static const struct object_ops sock_ops = no_lookup_name, /* lookup_name */ no_open_file, /* open_file */ + no_alloc_handle, /* alloc_handle */ - fd_close_handle, /* close_handle */ + sock_close_handle, /* close_handle */ sock_destroy /* destroy */ }; -@@ -626,6 +628,47 @@ static struct fd *sock_get_fd( struct object *obj ) +@@ -627,6 +629,47 @@ static struct fd *sock_get_fd( struct object *obj ) return (struct fd *)grab_object( sock->fd ); } @@ -160,7 +160,7 @@ index 1767dea..0f029bf 100644 static void sock_destroy( struct object *obj ) { struct sock *sock = (struct sock *)obj; -@@ -677,15 +720,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne +@@ -678,15 +721,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne struct sock *sock; int sockfd; @@ -177,7 +177,7 @@ index 1767dea..0f029bf 100644 if (!(sock = alloc_object( &sock_ops ))) { close( sockfd ); -@@ -1261,6 +1297,17 @@ DECL_HANDLER(accept_into_socket) +@@ -1263,6 +1299,17 @@ DECL_HANDLER(accept_into_socket) release_object( sock ); } @@ -196,5 +196,5 @@ index 1767dea..0f029bf 100644 DECL_HANDLER(set_socket_event) { -- -2.6.1 +2.6.2 diff --git a/patches/ws2_32-TransmitFile/definition b/patches/ws2_32-TransmitFile/definition index f54cc82d..dde30b29 100644 --- a/patches/ws2_32-TransmitFile/definition +++ b/patches/ws2_32-TransmitFile/definition @@ -1 +1,2 @@ # Fixes: [5048] Support for TransmitFile +Depends: server-Desktop_Refcount diff --git a/staging/changelog b/staging/changelog index 96fcf2ce..bb185d16 100644 --- a/staging/changelog +++ b/staging/changelog @@ -8,6 +8,8 @@ wine-staging (1.8~rc3) UNRELEASED; urgency=low upstream). * Removed patch to show windows version when collecting system info in winedbg (accepted upstream). + * Added patch to fix possible leak of explorer.exe processes and implement + proper desktop refcounting. -- Sebastian Lackner Tue, 01 Dec 2015 02:35:10 +0100 wine-staging (1.8~rc2) unstable; urgency=low