obj->ops->close_handle can indirectly call shrink_handle_table, which will invalidate "entry". Therefore accessing entry->ptr is not valid, neither is comparing "entry" with table->entries, since table->entries might have been reallocated.
* * *
caught in action: https://gitlab.winehq.org/yshui/wine/-/jobs/175272#L3516
From: Yuxuan Shui yshui@codeweavers.com
obj->ops->close_handle can indirectly call shrink_handle_table, which will invalidate "entry". Therefore accessing entry->ptr is not valid, neither is comparing "entry" with table->entries, since table->entries might have been reallocated. --- server/handle.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/server/handle.c b/server/handle.c index e4e843f4e39..bbd8bdf6939 100644 --- a/server/handle.c +++ b/server/handle.c @@ -426,18 +426,22 @@ struct handle_table *copy_handle_table( struct process *process, struct process /* close a handle and decrement the refcount of the associated object */ unsigned int close_handle( struct process *process, obj_handle_t handle ) { - struct handle_table *table; + struct handle_table *table = handle_is_global(handle) ? global_table : process->handles; struct handle_entry *entry; struct object *obj; + int index;
if (!(entry = get_handle( process, handle ))) return STATUS_INVALID_HANDLE; if (entry->access & RESERVED_CLOSE_PROTECT) return STATUS_HANDLE_NOT_CLOSABLE; obj = entry->ptr; + index = entry - table->entries; if (!obj->ops->close_handle( obj, process, handle )) return STATUS_HANDLE_NOT_CLOSABLE; - entry->ptr = NULL; + + /* table might have been shrunk, so we need to get it again */ table = handle_is_global(handle) ? global_table : process->handles; - if (entry < table->entries + table->free) table->free = entry - table->entries; - if (entry == table->entries + table->last) shrink_handle_table( table ); + table->entries[index].ptr = NULL; + if (index < table->free) table->free = index; + if (index == table->last) shrink_handle_table( table ); release_object_from_handle( obj ); return STATUS_SUCCESS; }