]> granicus.if.org Git - vim/commitdiff
patch 8.1.1575: callbacks may be garbage collected v8.1.1575
authorBram Moolenaar <Bram@vim.org>
Thu, 20 Jun 2019 01:45:36 +0000 (03:45 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 20 Jun 2019 01:45:36 +0000 (03:45 +0200)
Problem:    Callbacks may be garbage collected.
Solution:   Set reference in callbacks. (Ozaki Kiichi, closes #4564)

13 files changed:
src/buffer.c
src/channel.c
src/eval.c
src/ex_cmds2.c
src/popupwin.c
src/proto/buffer.pro
src/proto/popupwin.pro
src/terminal.c
src/testdir/test_listener.vim
src/testdir/test_popupwin.vim
src/testdir/test_prompt_buffer.vim
src/userfunc.c
src/version.c

index c3911ae2bb9d4d011c088145abac1af4510d5d1e..ee68bc955a76aed812cd9dba90dbd3ac185c7004 100644 (file)
@@ -5962,3 +5962,48 @@ wipe_buffer(
     if (!aucmd)
        unblock_autocmds();
 }
+
+#if defined(FEAT_EVAL) || defined(PROTO)
+/*
+ * Mark references in functions of buffers.
+ */
+    int
+set_ref_in_buffers(int copyID)
+{
+    int                abort = FALSE;
+    buf_T      *bp;
+
+    FOR_ALL_BUFFERS(bp)
+    {
+       listener_T *lnr;
+       typval_T tv;
+
+       for (lnr = bp->b_listener; !abort && lnr != NULL; lnr = lnr->lr_next)
+       {
+           if (lnr->lr_callback.cb_partial != NULL)
+           {
+               tv.v_type = VAR_PARTIAL;
+               tv.vval.v_partial = lnr->lr_callback.cb_partial;
+               abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+           }
+       }
+# ifdef FEAT_JOB_CHANNEL
+       if (!abort && bp->b_prompt_callback.cb_partial != NULL)
+       {
+           tv.v_type = VAR_PARTIAL;
+           tv.vval.v_partial = bp->b_prompt_callback.cb_partial;
+           abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+       }
+       if (!abort && bp->b_prompt_interrupt.cb_partial != NULL)
+       {
+           tv.v_type = VAR_PARTIAL;
+           tv.vval.v_partial = bp->b_prompt_interrupt.cb_partial;
+           abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+       }
+# endif
+       if (abort)
+           break;
+    }
+    return abort;
+}
+#endif
index 76c56114545a2d21f2c3a38337269763fbdcf722..4e6df94274c51281968cbb53b894eab314213594 100644 (file)
@@ -4479,7 +4479,8 @@ set_ref_in_channel(int copyID)
     channel_T  *channel;
     typval_T   tv;
 
-    for (channel = first_channel; channel != NULL; channel = channel->ch_next)
+    for (channel = first_channel; !abort && channel != NULL;
+                                                  channel = channel->ch_next)
        if (channel_still_useful(channel))
        {
            tv.v_type = VAR_CHANNEL;
@@ -5568,7 +5569,7 @@ set_ref_in_job(int copyID)
     job_T      *job;
     typval_T   tv;
 
-    for (job = first_job; job != NULL; job = job->jv_next)
+    for (job = first_job; !abort && job != NULL; job = job->jv_next)
        if (job_still_useful(job))
        {
            tv.v_type = VAR_JOB;
index 43866e657e737cc8337d9326dcc8ca1a505cc5f3..085e7d7e9a9984c178f8c38279f74e4bfa4d84fb 100644 (file)
@@ -5678,6 +5678,9 @@ garbage_collect(int testing)
     /* v: vars */
     abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL);
 
+    // callbacks in buffers
+    abort = abort || set_ref_in_buffers(copyID);
+
 #ifdef FEAT_LUA
     abort = abort || set_ref_in_lua(copyID);
 #endif
@@ -5710,6 +5713,10 @@ garbage_collect(int testing)
     abort = abort || set_ref_in_term(copyID);
 #endif
 
+#ifdef FEAT_TEXT_PROP
+    abort = abort || set_ref_in_popups(copyID);
+#endif
+
     if (!abort)
     {
        /*
index af7aa4b8ea6fb7b8850d0cbb1def7c3c62e66c93..2537e8d7b4ae912323aac24ef9577aaa2fd74778 100644 (file)
@@ -566,7 +566,7 @@ set_ref_in_timer(int copyID)
     timer_T    *timer;
     typval_T   tv;
 
-    for (timer = first_timer; timer != NULL; timer = timer->tr_next)
+    for (timer = first_timer; !abort && timer != NULL; timer = timer->tr_next)
     {
        if (timer->tr_callback.cb_partial != NULL)
        {
index e1fc0a7f42c4929a9f96fc4e89a6ae2f4ebc3b60..b6bb593ea9c57e9b8f8feec481e3409987ffff5c 100644 (file)
@@ -2140,4 +2140,50 @@ update_popups(void (*win_update)(win_T *wp))
     }
 }
 
+/*
+ * Mark references in callbacks of one popup window.
+ */
+    static int
+set_ref_in_one_popup(win_T *wp, int copyID)
+{
+    int                abort = FALSE;
+    typval_T   tv;
+
+    if (wp->w_close_cb.cb_partial != NULL)
+    {
+       tv.v_type = VAR_PARTIAL;
+       tv.vval.v_partial = wp->w_close_cb.cb_partial;
+       abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+    }
+    if (wp->w_filter_cb.cb_partial != NULL)
+    {
+       tv.v_type = VAR_PARTIAL;
+       tv.vval.v_partial = wp->w_filter_cb.cb_partial;
+       abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
+    }
+    return abort;
+}
+
+/*
+ * Set reference in callbacks of popup windows.
+ */
+    int
+set_ref_in_popups(int copyID)
+{
+    int                abort = FALSE;
+    win_T      *wp;
+    tabpage_T  *tp;
+
+    for (wp = first_popupwin; !abort && wp != NULL; wp = wp->w_next)
+       abort = abort || set_ref_in_one_popup(wp, copyID);
+
+    FOR_ALL_TABPAGES(tp)
+    {
+       for (wp = tp->tp_first_popupwin; !abort && wp != NULL; wp = wp->w_next)
+           abort = abort || set_ref_in_one_popup(wp, copyID);
+       if (abort)
+           break;
+    }
+    return abort;
+}
 #endif // FEAT_TEXT_PROP
index 81be7e4bd03f849accc9213e162d0aaf1b65d58f..45fcf2b56ede609b144c86dd0d53f6be1ba4bc4d 100644 (file)
@@ -74,4 +74,5 @@ int find_win_for_buf(buf_T *buf, win_T **wp, tabpage_T **tp);
 void set_buflisted(int on);
 int buf_contents_changed(buf_T *buf);
 void wipe_buffer(buf_T *buf, int aucmd);
+int set_ref_in_buffers(int copyID);
 /* vim: set ft=c : */
index 6c5ea46751b0b7aff601cf006be1b124ecdf513c..2f669468ffab45dc6fe205be5e9b2f8223e554e0 100644 (file)
@@ -31,4 +31,5 @@ int popup_do_filter(int c);
 void popup_check_cursor_pos(void);
 void may_update_popup_mask(int type);
 void update_popups(void (*win_update)(win_T *wp));
+int set_ref_in_popups(int copyID);
 /* vim: set ft=c : */
index 21026e2f744d766dd3824db929aa07bb998dc009..3511e0c805bfe54b889d05819d30c05322fed756 100644 (file)
@@ -4051,7 +4051,7 @@ set_ref_in_term(int copyID)
     term_T     *term;
     typval_T   tv;
 
-    for (term = first_term; term != NULL; term = term->tl_next)
+    for (term = first_term; !abort && term != NULL; term = term->tl_next)
        if (term->tl_job != NULL)
        {
            tv.v_type = VAR_JOB;
index a318d527aef6a14660f51bd13de85f8c3a3caab8..ed501c2ef80d58733b64f384d167f15d6efd1bad 100644 (file)
@@ -225,3 +225,20 @@ func Test_listening_other_buf()
   exe "buf " .. bufnr
   bwipe!
 endfunc
+
+func Test_listener_garbage_collect()
+  func MyListener(x, bufnr, start, end, added, changes)
+    " NOP
+  endfunc
+
+  new
+  let id = listener_add(function('MyListener', [{}]), bufnr(''))
+  call test_garbagecollect_now()
+  " must not crach caused by invalid memory access
+  normal ia
+  call assert_true(v:true)
+
+  call listener_remove(id)
+  delfunc MyListener
+  bwipe!
+endfunc
index 451f0b6b92a627a0c0f0f37bd44db91cd2aa7887..c332dcaaa70fdd1047e4c207c454f002df079fc7 100644 (file)
@@ -1467,3 +1467,19 @@ func Test_set_get_options()
 
   call popup_close(winid)
 endfunc
+
+func Test_popupwin_garbage_collect()
+  func MyPopupFilter(x, winid, c)
+    " NOP
+  endfunc
+
+  let winid = popup_create('something', {'filter': function('MyPopupFilter', [{}])})
+  call test_garbagecollect_now()
+  redraw
+  " Must not crach caused by invalid memory access
+  call feedkeys('j', 'xt')
+  call assert_true(v:true)
+
+  call popup_close(winid)
+  delfunc MyPopupFilter
+endfunc
index 58be50bcbf58e11126c737ca1fd09de271d59009..028f3371e3ad4d99139146eab234addbf7fdc64a 100644 (file)
@@ -102,3 +102,24 @@ func Test_prompt_editing()
   call StopVimInTerminal(buf)
   call delete(scriptName)
 endfunc
+
+func Test_prompt_garbage_collect()
+  func MyPromptCallback(x, text)
+    " NOP
+  endfunc
+  func MyPromptInterrupt(x)
+    " NOP
+  endfunc
+
+  new
+  set buftype=prompt
+  call prompt_setcallback(bufnr(''), function('MyPromptCallback', [{}]))
+  call prompt_setinterrupt(bufnr(''), function('MyPromptInterrupt', [{}]))
+  call test_garbagecollect_now()
+  " Must not crash
+  call feedkeys("\<CR>\<C-C>", 'xt')
+  call assert_true(v:true)
+
+  delfunc MyPromptCallback
+  bwipe!
+endfunc
index 197e2e06315b1ce6e2e918d1bd850844a73f9076..8d1df0ca8b25f5a6dbaec0ce0df0abca64033833 100644 (file)
@@ -4032,12 +4032,12 @@ set_ref_in_call_stack(int copyID)
     funccall_T         *fc;
     funccal_entry_T    *entry;
 
-    for (fc = current_funccal; fc != NULL; fc = fc->caller)
+    for (fc = current_funccal; !abort && fc != NULL; fc = fc->caller)
        abort = abort || set_ref_in_funccal(fc, copyID);
 
     // Also go through the funccal_stack.
-    for (entry = funccal_stack; entry != NULL; entry = entry->next)
-       for (fc = entry->top_funccal; fc != NULL; fc = fc->caller)
+    for (entry = funccal_stack; !abort && entry != NULL; entry = entry->next)
+       for (fc = entry->top_funccal; !abort && fc != NULL; fc = fc->caller)
            abort = abort || set_ref_in_funccal(fc, copyID);
 
     return abort;
index 41db458d6c688ac84f814ce06cc138c887149fa1..019be44bad6e56d61a2c00d14d21436567815260 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1575,
 /**/
     1574,
 /**/