]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.2.0802: Memory leak with list_append_dict/dict_add_list on alloc failure v9.2.0802
authorYasuhiro Matsumoto <mattn.jp@gmail.com>
Sat, 18 Jul 2026 14:37:14 +0000 (14:37 +0000)
committerChristian Brabandt <cb@256bit.org>
Sat, 18 Jul 2026 14:37:14 +0000 (14:37 +0000)
Problem:  Memory leak with list_append_dict()/dict_add_list() on alloc
          failure
Solution: Free the list/dict when dict_add_list()/list_append_dict()
          failed (Yasuhiro Matsumoto)

Various getinfo-style builtins ignored the return of list_append_dict()/
dict_add_list() and leaked the freshly allocated, GC-linked dict or list on
allocation failure. Check the return and unref on failure. Affects
getreginfo/setreg event (register.c), hlget (highlight.c), prop_list
(textprop.c), getmatches (match.c), menu_getinfo (menu.c),
popup_getoptions (popupwin.c), sign_getplaced (sign.c), job_info (job.c),
term_getcursor/term_scrape (terminal.c), diff() (diff.c), complete_info
(insexpand.c), cmdcomplete_info (cmdexpand.c).

related: #20668
related: #20745

Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
13 files changed:
src/cmdexpand.c
src/diff.c
src/highlight.c
src/insexpand.c
src/job.c
src/match.c
src/menu.c
src/popupwin.c
src/register.c
src/sign.c
src/terminal.c
src/textprop.c
src/version.c

index 97829937583f88d8ed553800f9b9211ba8ca7765..34edf25ef0113ac491bb42f8830072b3f8ba7da0 100644 (file)
@@ -5042,6 +5042,8 @@ f_cmdcomplete_info(typval_T *argvars UNUSED, typval_T *rettv)
        if (li == NULL)
            return;
        ret = dict_add_list(retdict, "matches", li);
+       if (ret == FAIL)
+           list_unref(li);
        for (idx = 0; ret == OK && idx < ccline->xpc->xp_numfiles; idx++)
            list_append_string(li, ccline->xpc->xp_files[idx], -1);
     }
index a29c434110f9365b4c820e6b8ea7d1429b7f3fca..b38513693e4cc4655ffbf5216cd08a07a1de4a2e 100644 (file)
@@ -5140,7 +5140,8 @@ f_diff(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
            if (hunk_dict == NULL)
                goto done;
 
-           list_append_dict(l, hunk_dict);
+           if (list_append_dict(l, hunk_dict) == FAIL)
+               dict_unref(hunk_dict);
        }
     }
     else
index f2982bacaac1e2f6f4f342fc43caba8f4fd89072..cfed85de336b7f38f2b0e346de40fa790314411a 100644 (file)
@@ -5768,8 +5768,8 @@ f_hlget(typval_T *argvars, typval_T *rettv)
        if (hlarg == NULL || STRICMP(hlarg, HL_TABLE()[i].sg_name) == 0)
        {
            dict = highlight_get_info(i, resolve_link);
-           if (dict != NULL)
-               list_append_dict(list, dict);
+           if (dict != NULL && list_append_dict(list, dict) == FAIL)
+               dict_unref(dict);
        }
     }
 }
index e566ee5044a536019373cdadca1306a11027421a..0833340c70a5fcc33f3e52be5f4bf265461410af 100644 (file)
@@ -4176,6 +4176,8 @@ get_complete_info(list_T *what_list, dict_T *retdict)
                return;
            ret = dict_add_list(retdict, (has_matches && !has_items)
                                                ? "matches" : "items", li);
+           if (ret == FAIL)
+               list_unref(li);
        }
        if (ret == OK && what_flag & CI_WHAT_SELECTED)
            if (compl_curr_match != NULL && compl_curr_match->cp_number == -1)
@@ -4196,7 +4198,10 @@ get_complete_info(list_T *what_list, dict_T *retdict)
                            return;
                        ret = list_append_dict(li, di);
                        if (ret != OK)
+                       {
+                           dict_unref(di);
                            return;
+                       }
                        fill_complete_info_dict(di, match, has_matches && has_items);
                    }
                    if (compl_curr_match != NULL
@@ -4219,6 +4224,8 @@ get_complete_info(list_T *what_list, dict_T *retdict)
                return;
            fill_complete_info_dict(di, compl_curr_match, FALSE);
            ret = dict_add_dict(retdict, "completed", di);
+           if (ret == FAIL)
+               dict_unref(di);
        }
     }
 }
index c7c546aa3879b96abaac03bf8853268c91a39861..7ab7884246e992875f212f7539611c3af1d7a1c7 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -1870,7 +1870,11 @@ job_info(job_T *job, dict_T *dict)
     if (l == NULL)
        return;
 
-    dict_add_list(dict, "cmd", l);
+    if (dict_add_list(dict, "cmd", l) == FAIL)
+    {
+       list_unref(l);
+       return;
+    }
     if (job->jv_argv != NULL)
        for (i = 0; job->jv_argv[i] != NULL; i++)
            list_append_string(l, (char_u *)job->jv_argv[i], -1);
index 709ac30495ab819897283d2ef2d64335da914ccb..6bd5ff8d900103815e655d527b339bcac2f3648b 100644 (file)
@@ -1035,7 +1035,8 @@ f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
                    list_append_number(l, (varnumber_T)llpos->len);
                }
                sprintf(buf, "pos%d", i + 1);
-               dict_add_list(dict, buf, l);
+               if (dict_add_list(dict, buf, l) == FAIL)
+                   list_unref(l);
            }
        }
        else
@@ -1056,7 +1057,8 @@ f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
            dict_add_string_len(dict, "conceal", (char_u *)&buf, buflen);
        }
 #  endif
-       list_append_dict(rettv->vval.v_list, dict);
+       if (list_append_dict(rettv->vval.v_list, dict) == FAIL)
+           dict_unref(dict);
        cur = cur->mit_next;
     }
 # endif
index 861d787112ec66256fedeeb4ce7f6b1d0c91d6cf..ddb381c62a482f3403277dc32d2839706e106490 100644 (file)
@@ -2862,7 +2862,11 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu, int modes, dict_T *dict)
        if (l == NULL)
            return FAIL;
 
-       dict_add_list(dict, "submenus", l);
+       if (dict_add_list(dict, "submenus", l) == FAIL)
+       {
+           list_unref(l);
+           return FAIL;
+       }
        // get all the children.  Skip PopUp[nvoci].
        for (topmenu = menu; topmenu != NULL; topmenu = topmenu->next)
            if (!menu_is_hidden(topmenu->dname))
@@ -2950,7 +2954,11 @@ menuitem_getinfo(char_u *menu_name, vimmenu_T *menu, int modes, dict_T *dict)
        if (l == NULL)
            return FAIL;
 
-       dict_add_list(dict, "submenus", l);
+       if (dict_add_list(dict, "submenus", l) == FAIL)
+       {
+           list_unref(l);
+           return FAIL;
+       }
        child = menu->children;
        while (child)
        {
index 96fa7895a1babe8af6ad91d343519e33ffd75900..cd3fe80dab80a8fbe8a22412de8ea6d3f7c4f80c 100644 (file)
@@ -5344,7 +5344,11 @@ get_padding_border(dict_T *dict, int *array, char *name)
     if (list == NULL)
        return;
 
-    dict_add_list(dict, name, list);
+    if (dict_add_list(dict, name, list) == FAIL)
+    {
+       list_unref(list);
+       return;
+    }
     if (array[0] != 1 || array[1] != 1 || array[2] != 1 || array[3] != 1)
        for (i = 0; i < 4; ++i)
            list_append_number(list, array[i]);
@@ -5371,7 +5375,11 @@ get_borderhighlight(dict_T *dict, win_T *wp)
     if (list == NULL)
        return;
 
-    dict_add_list(dict, "borderhighlight", list);
+    if (dict_add_list(dict, "borderhighlight", list) == FAIL)
+    {
+       list_unref(list);
+       return;
+    }
     // When all highlights are NULL (cleared to empty list), return empty list.
     if (i == 4)
        return;
@@ -5400,7 +5408,11 @@ get_borderchars(dict_T *dict, win_T *wp)
     if (list == NULL)
        return;
 
-    dict_add_list(dict, "borderchars", list);
+    if (dict_add_list(dict, "borderchars", list) == FAIL)
+    {
+       list_unref(list);
+       return;
+    }
     for (i = 0; i < 8; ++i)
     {
        len = mb_char2bytes(wp->w_border_char[i], buf);
@@ -5419,16 +5431,24 @@ get_moved_list(dict_T *dict, win_T *wp)
     list = list_alloc();
     if (list != NULL)
     {
-       dict_add_list(dict, "moved", list);
-       list_append_number(list, wp->w_popup_lnum);
-       list_append_number(list, wp->w_popup_mincol);
-       list_append_number(list, wp->w_popup_maxcol);
+       if (dict_add_list(dict, "moved", list) == FAIL)
+           list_unref(list);
+       else
+       {
+           list_append_number(list, wp->w_popup_lnum);
+           list_append_number(list, wp->w_popup_mincol);
+           list_append_number(list, wp->w_popup_maxcol);
+       }
     }
     list = list_alloc();
     if (list == NULL)
        return;
 
-    dict_add_list(dict, "mousemoved", list);
+    if (dict_add_list(dict, "mousemoved", list) == FAIL)
+    {
+       list_unref(list);
+       return;
+    }
     list_append_number(list, wp->w_popup_mouse_row);
     list_append_number(list, wp->w_popup_mouse_mincol);
     list_append_number(list, wp->w_popup_mouse_maxcol);
index 5d22dc34a8f04f1fceb355f4213b83a5125508bb..4ccb68b82621c07a351eea1d8caeefa80080bca6 100644 (file)
@@ -1134,7 +1134,8 @@ yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
     for (n = 0; n < reg->y_size; n++)
        list_append_string(list, reg->y_array[n].string, (int)reg->y_array[n].length);
     list->lv_lock = VAR_FIXED;
-    (void)dict_add_list(v_event, "regcontents", list);
+    if (dict_add_list(v_event, "regcontents", list) == FAIL)
+       list_unref(list);
 
     // register name or empty string for unnamed operation
     buf[0] = (char_u)oap->regname;
@@ -1229,7 +1230,8 @@ put_do_autocmd(
     }
 
     list->lv_lock = VAR_FIXED;
-    (void)dict_add_list(v_event, "regcontents", list);
+    if (dict_add_list(v_event, "regcontents", list) == FAIL)
+       list_unref(list);
 
     // register name or empty string for unnamed operation
     buf[0] = (char_u)regname;
index 1d735de001460eef6feb09dafff34fde6d6276a3..fc701d1ed61a32d39b557e45ed4a07a614bacf8e 100644 (file)
@@ -1860,8 +1860,8 @@ get_buffer_signs(buf_T *buf, list_T *l)
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
     {
         dict_T *d = sign_get_info(sign);
-        if (d != NULL)
-            list_append_dict(l, d);
+        if (d != NULL && list_append_dict(l, d) == FAIL)
+            dict_unref(d);
     }
 }
 
@@ -1879,7 +1879,11 @@ sign_get_placed_in_buf(buf_T *buf,
     if (d == NULL)
         return;
 
-    list_append_dict(retlist, d);
+    if (list_append_dict(retlist, d) == FAIL)
+    {
+        dict_unref(d);
+        return;
+    }
 
     dict_add_number(d, "bufnr", (long)buf->b_fnum);
 
@@ -1887,7 +1891,11 @@ sign_get_placed_in_buf(buf_T *buf,
     if (l == NULL)
         return;
 
-    dict_add_list(d, "signs", l);
+    if (dict_add_list(d, "signs", l) == FAIL)
+    {
+        list_unref(l);
+        return;
+    }
 
     sign_entry_T *sign = NULL;
     FOR_ALL_SIGNS_IN_BUF(buf, sign)
@@ -1901,8 +1909,8 @@ sign_get_placed_in_buf(buf_T *buf,
             (lnum == sign->se_lnum && sign_id == sign->se_id))
         {
             dict_T *sdict = sign_get_info(sign);
-            if (sdict != NULL)
-                list_append_dict(l, sdict);
+            if (sdict != NULL && list_append_dict(l, sdict) == FAIL)
+                dict_unref(sdict);
         }
     }
 }
index 5ec9b71a655a8037405e15fbf8d69dba1c2f928f..2a2932a8844c6cb0e4fd89ef6a5e7a71b6ae92a9 100644 (file)
@@ -6435,7 +6435,8 @@ f_term_getcursor(typval_T *argvars, typval_T *rettv)
            ? !term->tl_cursor_blink : term->tl_cursor_blink);
     dict_add_number(d, "shape", term->tl_cursor_shape);
     dict_add_string(d, "color", cursor_color_get(term->tl_cursor_color));
-    list_append_dict(l, d);
+    if (list_append_dict(l, d) == FAIL)
+       dict_unref(d);
 }
 
 /*
@@ -6846,7 +6847,11 @@ f_term_scrape(typval_T *argvars, typval_T *rettv)
        dcell = dict_alloc();
        if (dcell == NULL)
            break;
-       list_append_dict(l, dcell);
+       if (list_append_dict(l, dcell) == FAIL)
+       {
+           dict_unref(dcell);
+           break;
+       }
 
        dict_add_string_len(dcell, "chars", mbs, (int)mbslen);
 
index 6d5a108631b3718fef92c796258feb39d503cfa7..4d3c8d2d710b23e6748b471e9706c565dc35eeb8 100644 (file)
@@ -2153,7 +2153,8 @@ get_props_in_line(
            prop_fill_dict(d, &prop, buf);
            if (add_lnum)
                dict_add_number(d, "lnum", lnum);
-           list_append_dict(retlist, d);
+           if (list_append_dict(retlist, d) == FAIL)
+               dict_unref(d);
        }
     }
 }
index e5eaed8d967b2b5d1ef3866d13ab3612ee693820..c64e48f0839e8842abfe7d806453421a76f79875 100644 (file)
@@ -759,6 +759,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    802,
 /**/
     801,
 /**/