Mercurial > vim
diff src/testdir/test_iminsert.vim @ 26518:13ba00ef7687 v8.2.3788
patch 8.2.3788: lambda for option that is a function may be freed
Commit: https://github.com/vim/vim/commit/6ae8fae8696623b527c7fb22567f6a3705b2f0dd
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sun Dec 12 16:26:44 2021 +0000
patch 8.2.3788: lambda for option that is a function may be freed
Problem: Lambda for option that is a function may be garbage collected.
Solution: Set a reference in the funcref. (Yegappan Lakshmanan,
closes #9330)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sun, 12 Dec 2021 17:30:04 +0100 |
parents | 65b4109a4297 |
children | 33d680d372aa |
line wrap: on
line diff
--- a/src/testdir/test_iminsert.vim +++ b/src/testdir/test_iminsert.vim @@ -119,83 +119,142 @@ func Test_imactivatefunc_imstatusfunc_ca let g:IMstatusfunc_called += 1 return 1 endfunc - let g:IMactivatefunc_called = 0 - let g:IMstatusfunc_called = 0 set iminsert=2 - " Test for using a function() - set imactivatefunc=function('IMactivatefunc1') - set imstatusfunc=function('IMstatusfunc1') - normal! i + let lines =<< trim END + LET g:IMactivatefunc_called = 0 + LET g:IMstatusfunc_called = 0 + + #" Test for using a function() + set imactivatefunc=function('g:IMactivatefunc1') + set imstatusfunc=function('g:IMstatusfunc1') + normal! i - " Using a funcref variable to set 'completefunc' - let Fn1 = function('IMactivatefunc1') - let &imactivatefunc = Fn1 - let Fn2 = function('IMstatusfunc1') - let &imstatusfunc = Fn2 - normal! i + #" Using a funcref variable to set 'completefunc' + VAR Fn1 = function('g:IMactivatefunc1') + LET &imactivatefunc = Fn1 + VAR Fn2 = function('g:IMstatusfunc1') + LET &imstatusfunc = Fn2 + normal! i - " Using a string(funcref variable) to set 'completefunc' - let &imactivatefunc = string(Fn1) - let &imstatusfunc = string(Fn2) - normal! i + #" Using a string(funcref variable) to set 'completefunc' + LET &imactivatefunc = string(Fn1) + LET &imstatusfunc = string(Fn2) + normal! i + + #" Test for using a funcref() + set imactivatefunc=funcref('g:IMactivatefunc1') + set imstatusfunc=funcref('g:IMstatusfunc1') + normal! i - " Test for using a funcref() - set imactivatefunc=funcref('IMactivatefunc1') - set imstatusfunc=funcref('IMstatusfunc1') - normal! i + #" Using a funcref variable to set 'imactivatefunc' + LET Fn1 = funcref('g:IMactivatefunc1') + LET &imactivatefunc = Fn1 + LET Fn2 = funcref('g:IMstatusfunc1') + LET &imstatusfunc = Fn2 + normal! i + + #" Using a string(funcref variable) to set 'imactivatefunc' + LET &imactivatefunc = string(Fn1) + LET &imstatusfunc = string(Fn2) + normal! i - " Using a funcref variable to set 'imactivatefunc' - let Fn1 = funcref('IMactivatefunc1') - let &imactivatefunc = Fn1 - let Fn2 = funcref('IMstatusfunc1') - let &imstatusfunc = Fn2 - normal! i + #" Test for using a lambda function + VAR optval = "LSTART a LMIDDLE IMactivatefunc1(a) LEND" + LET optval = substitute(optval, ' ', '\\ ', 'g') + exe "set imactivatefunc=" .. optval + LET optval = "LSTART LMIDDLE IMstatusfunc1() LEND" + LET optval = substitute(optval, ' ', '\\ ', 'g') + exe "set imstatusfunc=" .. optval + normal! i - " Using a string(funcref variable) to set 'imactivatefunc' - let &imactivatefunc = string(Fn1) - let &imstatusfunc = string(Fn2) - normal! i + #" Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression + LET &imactivatefunc = LSTART a LMIDDLE IMactivatefunc1(a) LEND + LET &imstatusfunc = LSTART LMIDDLE IMstatusfunc1() LEND + normal! i + + #" Set 'imactivatefunc' and 'imstatusfunc' to a string(lambda expression) + LET &imactivatefunc = 'LSTART a LMIDDLE IMactivatefunc1(a) LEND' + LET &imstatusfunc = 'LSTART LMIDDLE IMstatusfunc1() LEND' + normal! i + + #" Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda + #" expression + VAR Lambda1 = LSTART a LMIDDLE IMactivatefunc1(a) LEND + VAR Lambda2 = LSTART LMIDDLE IMstatusfunc1() LEND + LET &imactivatefunc = Lambda1 + LET &imstatusfunc = Lambda2 + normal! i - " Test for using a lambda function - set imactivatefunc={a\ ->\ IMactivatefunc1(a)} - set imstatusfunc={\ ->\ IMstatusfunc1()} - normal! i + #" Set 'imactivatefunc' 'imstatusfunc' to a string(variable with a lambda + #" expression) + LET &imactivatefunc = string(Lambda1) + LET &imstatusfunc = string(Lambda2) + normal! i + + #" Test for clearing the 'completefunc' option + set imactivatefunc='' imstatusfunc='' + set imactivatefunc& imstatusfunc& - " Set 'imactivatefunc' and 'imstatusfunc' to a lambda expression - let &imactivatefunc = {a -> IMactivatefunc1(a)} - let &imstatusfunc = { -> IMstatusfunc1()} - normal! i + set imactivatefunc=g:IMactivatefunc1 + set imstatusfunc=g:IMstatusfunc1 + call assert_fails("set imactivatefunc=function('abc')", "E700:") + call assert_fails("set imstatusfunc=function('abc')", "E700:") + call assert_fails("set imactivatefunc=funcref('abc')", "E700:") + call assert_fails("set imstatusfunc=funcref('abc')", "E700:") + call assert_fails("LET &imstatusfunc = function('abc')", "E700:") + call assert_fails("LET &imactivatefunc = function('abc')", "E700:") + normal! i - " Set 'imactivatefunc' and 'imstatusfunc' to a string(lambda expression) - let &imactivatefunc = '{a -> IMactivatefunc1(a)}' - let &imstatusfunc = '{ -> IMstatusfunc1()}' - normal! i + #" set 'imactivatefunc' and 'imstatusfunc' to a non-existing function + set imactivatefunc=IMactivatefunc1 + set imstatusfunc=IMstatusfunc1 + call assert_fails("set imactivatefunc=function('NonExistingFunc')", 'E700:') + call assert_fails("set imstatusfunc=function('NonExistingFunc')", 'E700:') + call assert_fails("LET &imactivatefunc = function('NonExistingFunc')", 'E700:') + call assert_fails("LET &imstatusfunc = function('NonExistingFunc')", 'E700:') + normal! i + + call assert_equal(13, g:IMactivatefunc_called) + call assert_equal(26, g:IMstatusfunc_called) + END + call CheckLegacyAndVim9Success(lines) - " Set 'imactivatefunc' 'imstatusfunc' to a variable with a lambda expression - let Lambda1 = {a -> IMactivatefunc1(a)} - let Lambda2 = { -> IMstatusfunc1()} - let &imactivatefunc = Lambda1 - let &imstatusfunc = Lambda2 - normal! i + " Using Vim9 lambda expression in legacy context should fail + set imactivatefunc=(a)\ =>\ IMactivatefunc1(a) + set imstatusfunc=IMstatusfunc1 + call assert_fails('normal! i', 'E117:') + set imactivatefunc=IMactivatefunc1 + set imstatusfunc=()\ =>\ IMstatusfunc1(a) + call assert_fails('normal! i', 'E117:') - " Set 'imactivatefunc' 'imstatusfunc' to a string(variable with a lambda - " expression) - let &imactivatefunc = string(Lambda1) - let &imstatusfunc = string(Lambda2) - normal! i - - " Test for clearing the 'completefunc' option - set imactivatefunc='' imstatusfunc='' - set imactivatefunc& imstatusfunc& - - call assert_fails("set imactivatefunc=function('abc')", "E700:") - call assert_fails("set imstatusfunc=function('abc')", "E700:") - call assert_fails("set imactivatefunc=funcref('abc')", "E700:") - call assert_fails("set imstatusfunc=funcref('abc')", "E700:") - - call assert_equal(11, g:IMactivatefunc_called) - call assert_equal(22, g:IMstatusfunc_called) + " set 'imactivatefunc' and 'imstatusfunc' to a partial with dict. This used + " to cause a crash. + func SetIMFunc() + let params1 = {'activate': function('g:DictActivateFunc')} + let params2 = {'status': function('g:DictStatusFunc')} + let &imactivatefunc = params1.activate + let &imstatusfunc = params2.status + endfunc + func g:DictActivateFunc(_) dict + endfunc + func g:DictStatusFunc(_) dict + endfunc + call SetIMFunc() + new + call SetIMFunc() + bw + call test_garbagecollect_now() + new + set imactivatefunc= + set imstatusfunc= + wincmd w + set imactivatefunc= + set imstatusfunc= + :%bw! + delfunc g:DictActivateFunc + delfunc g:DictStatusFunc + delfunc SetIMFunc " Vim9 tests let lines =<< trim END @@ -217,59 +276,12 @@ func Test_imactivatefunc_imstatusfunc_ca set imstatusfunc=function('IMstatusfunc1') normal! i - # Test for using a lambda - &imactivatefunc = '(a) => IMactivatefunc1(a)' - &imstatusfunc = '() => IMstatusfunc1()' - normal! i - - # Test for using a variable with a lambda expression - var Fn1: func = (active) => { - g:IMactivatefunc_called += 1 - return 1 - } - var Fn2: func = () => { - g:IMstatusfunc_called += 1 - return 1 - } - &imactivatefunc = Fn1 - &imstatusfunc = Fn2 - normal! i - - # Test for using a string(variable with a lambda expression) - &imactivatefunc = string(Fn1) - &imstatusfunc = string(Fn2) - normal! i - - assert_equal(4, g:IMactivatefunc_called) - assert_equal(8, g:IMstatusfunc_called) - set iminsert=0 set imactivatefunc= set imstatusfunc= END call CheckScriptSuccess(lines) - " Using Vim9 lambda expression in legacy context should fail - set imactivatefunc=(a)\ =>\ IMactivatefunc1(a) - set imstatusfunc=IMstatusfunc1 - call assert_fails('normal! i', 'E117:') - set imactivatefunc=IMactivatefunc1 - set imstatusfunc=()\ =>\ IMstatusfunc1(a) - call assert_fails('normal! i', 'E117:') - - " set 'imactivatefunc' and 'imstatusfunc' to a non-existing function - set imactivatefunc=IMactivatefunc1 - set imstatusfunc=IMstatusfunc1 - call assert_fails("set imactivatefunc=function('NonExistingFunc')", 'E700:') - call assert_fails("set imstatusfunc=function('NonExistingFunc')", 'E700:') - call assert_fails("let &imactivatefunc = function('NonExistingFunc')", 'E700:') - call assert_fails("let &imstatusfunc = function('NonExistingFunc')", 'E700:') - let g:IMactivatefunc_called = 0 - let g:IMstatusfunc_called = 0 - normal! i - call assert_equal(2, g:IMactivatefunc_called) - call assert_equal(2, g:IMstatusfunc_called) - " cleanup delfunc IMactivatefunc1 delfunc IMstatusfunc1