From 6f98352163057a0bea06d3859747a01558af3772 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 3 Jul 2026 15:16:40 +0800 Subject: [PATCH 1/2] vim-patch:9.2.0770: dict_add_dict() has inconsistent ownership on failure Problem: dict_add_dict() frees the passed dict on one failure path (when dict_add() fails) but not on the other (when dictitem_alloc() fails), so a caller cannot tell whether it still owns the dict after a failure. Callers that unref the dict on failure (e.g. in window.c) then double-free it when dict_add() fails. Solution: Make the failure contract consistent: on failure leave the passed dict untouched and owned by the caller; only take a reference on success. related: vim/vim#20668 Supported by AI. https://github.com/vim/vim/commit/12dbe788d461f7f01a908e9e9ecc844f85d71cb4 Co-authored-by: Christian Brabandt --- src/nvim/eval/typval.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 096f11a35b..ab560c041a 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2537,11 +2537,14 @@ int tv_dict_add_dict(dict_T *const d, const char *const key, const size_t key_le item->di_tv.v_type = VAR_DICT; item->di_tv.vval.v_dict = dict; - dict->dv_refcount++; if (tv_dict_add(d, item) == FAIL) { + // Detach "dict" so tv_dict_item_free() does not unref it: on failure + // ownership stays with the caller. + item->di_tv.vval.v_dict = NULL; tv_dict_item_free(item); return FAIL; } + dict->dv_refcount++; return OK; } From b856d5080d80d8bcfcb1cd459bac9f41484a63ea Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Fri, 3 Jul 2026 15:19:24 +0800 Subject: [PATCH 2/2] vim-patch:9.2.0771: dict_add_list() has inconsistent ownership on failure Problem: dict_add_list() frees the passed list on failure path (when dict_add() fails) but not on the other (when dictitem_alloc() fails), so a caller cannot tell whether it still owns the list after a failure. Solution: On failure leave the passed list untouched and owned by the caller; only take a reference on success. related: vim/vim#20668 Supported by AI. https://github.com/vim/vim/commit/3ae1443d10da03019d4b37c090daee38926da215 Co-authored-by: Christian Brabandt --- src/nvim/eval/typval.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index ab560c041a..c84c7a30ce 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -2494,11 +2494,14 @@ int tv_dict_add_list(dict_T *const d, const char *const key, const size_t key_le item->di_tv.v_type = VAR_LIST; item->di_tv.vval.v_list = list; - tv_list_ref(list); if (tv_dict_add(d, item) == FAIL) { + // Detach "list" so tv_dict_item_free() does not unref it: on failure + // ownership stays with the caller. + item->di_tv.vval.v_list = NULL; tv_dict_item_free(item); return FAIL; } + tv_list_ref(list); return OK; }