Mercurial > vim
view src/testdir/test_source.vim @ 33471:baa62f464436 v9.0.1988
patch 9.0.1988: Vim9: potential use-after-free for class members
Commit: https://github.com/vim/vim/commit/d2f4800099733216e28d59e1a5710f624b0d9ec1
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Thu Oct 5 20:24:18 2023 +0200
patch 9.0.1988: Vim9: potential use-after-free for class members
Problem: Vim9: potential use-after-free for class members
Solution: Use the class-related grow array for storing the
member type instead of using a temporary type
list grow array
Use the type list grow array associated with the class than using a
temporary type list grow array to allocate the class member type.
For simple types, a predefined type is used. For complex types, the type
is dynamically allocated from a grow array. For class variables, the
type grow array in the class should be used. So that the lifetime of the
type is same as the lifetime of the class.
closes: #13279
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Thu, 05 Oct 2023 20:30:11 +0200 |
parents | ae10b91ac6b3 |
children |
line wrap: on
line source
" Tests for the :source command. source check.vim source view_util.vim func Test_source_autocmd() call writefile([ \ 'let did_source = 1', \ ], 'Xsourced', 'D') au SourcePre *source* let did_source_pre = 1 au SourcePost *source* let did_source_post = 1 source Xsourced call assert_equal(g:did_source, 1) call assert_equal(g:did_source_pre, 1) call assert_equal(g:did_source_post, 1) au! SourcePre au! SourcePost unlet g:did_source unlet g:did_source_pre unlet g:did_source_post endfunc func Test_source_cmd() au SourceCmd *source* let did_source = expand('<afile>') au SourcePre *source* let did_source_pre = 2 au SourcePost *source* let did_source_post = 2 source Xsourced call assert_equal(g:did_source, 'Xsourced') call assert_false(exists('g:did_source_pre')) call assert_equal(g:did_source_post, 2) au! SourceCmd au! SourcePre au! SourcePost endfunc func Test_source_sandbox() new call writefile(["Ohello\<Esc>"], 'Xsourcehello', 'D') source! Xsourcehello | echo call assert_equal('hello', getline(1)) call assert_fails('sandbox source! Xsourcehello', 'E48:') bwipe! endfunc " When deleting a file and immediately creating a new one the inode may be " recycled. Vim should not recognize it as the same script. func Test_different_script() call writefile(['let s:var = "asdf"'], 'XoneScript', 'D') source XoneScript call writefile(['let g:var = s:var'], 'XtwoScript', 'D') call assert_fails('source XtwoScript', 'E121:') endfunc " When sourcing a vim script, shebang should be ignored. func Test_source_ignore_shebang() call writefile(['#!./xyzabc', 'let g:val=369'], 'Xsisfile.vim', 'D') source Xsisfile.vim call assert_equal(g:val, 369) endfunc " Test for expanding <sfile> in an autocmd and for <slnum> and <sflnum> func Test_source_autocmd_sfile() let code =<< trim [CODE] let g:SfileName = '' augroup sfiletest au! autocmd User UserAutoCmd let g:Sfile = '<sfile>:t' augroup END doautocmd User UserAutoCmd let g:Slnum = expand('<slnum>') let g:Sflnum = expand('<sflnum>') augroup! sfiletest [CODE] call writefile(code, 'Xscript.vim', 'D') source Xscript.vim call assert_equal('Xscript.vim', g:Sfile) call assert_equal('7', g:Slnum) call assert_equal('8', g:Sflnum) endfunc func Test_source_error() call assert_fails('scriptencoding utf-8', 'E167:') call assert_fails('finish', 'E168:') call assert_fails('scriptversion 2', 'E984:') call assert_fails('source!', 'E471:') new call setline(1, ['', '', '', '']) call assert_fails('1,3source Xscript.vim', 'E481:') call assert_fails('1,3source! Xscript.vim', 'E481:') bw! endfunc " Test for sourcing a script recursively func Test_nested_script() CheckRunVimInTerminal call writefile([':source! Xscript.vim', ''], 'Xscript.vim', 'D') let buf = RunVimInTerminal('', {'rows': 6}) call term_wait(buf) call term_sendkeys(buf, ":set noruler\n") call term_sendkeys(buf, ":source! Xscript.vim\n") call term_wait(buf) call WaitForAssert({-> assert_match('E22: Scripts nested too deep\s*', term_getline(buf, 6))}) call StopVimInTerminal(buf) endfunc " Test for sourcing a script from the current buffer func Test_source_buffer() new " Source a simple script let lines =<< trim END let a = "Test" let b = 20 let c = [1.1] END call setline(1, lines) source call assert_equal(['Test', 20, [1.1]], [g:a, g:b, g:c]) " Source a range of lines in the current buffer %d _ let lines =<< trim END let a = 10 let a += 20 let a += 30 let a += 40 END call setline(1, lines) .source call assert_equal(10, g:a) 3source call assert_equal(40, g:a) 2,3source call assert_equal(90, g:a) " Make sure the script line number is correct when sourcing a range of " lines. %d _ let lines =<< trim END Line 1 Line 2 func Xtestfunc() return expand("<sflnum>") endfunc Line 3 Line 4 END call setline(1, lines) 3,5source call assert_equal('4', Xtestfunc()) delfunc Xtestfunc " Source a script with line continuation lines %d _ let lines =<< trim END let m = [ \ 1, \ 2, \ ] call add(m, 3) END call setline(1, lines) source call assert_equal([1, 2, 3], g:m) " Source a script with line continuation lines and a comment %d _ let lines =<< trim END let m = [ "\ first entry \ 'a', "\ second entry \ 'b', \ ] " third entry call add(m, 'c') END call setline(1, lines) source call assert_equal(['a', 'b', 'c'], g:m) " Source an incomplete line continuation line %d _ let lines =<< trim END let k = [ \ END call setline(1, lines) call assert_fails('source', 'E697:') " Source a function with a for loop %d _ let lines =<< trim END let m = [] " test function func! Xtest() for i in range(5, 7) call add(g:m, i) endfor endfunc call Xtest() END call setline(1, lines) source call assert_equal([5, 6, 7], g:m) " Source an empty buffer %d _ source " test for script local functions and variables let lines =<< trim END let s:var1 = 10 func s:F1() let s:var1 += 1 return s:var1 endfunc func s:F2() endfunc let g:ScriptID = expand("<SID>") END call setline(1, lines) source call assert_true(g:ScriptID != '') call assert_true(exists('*' .. g:ScriptID .. 'F1')) call assert_true(exists('*' .. g:ScriptID .. 'F2')) call assert_equal(11, call(g:ScriptID .. 'F1', [])) " the same script ID should be used even if the buffer is sourced more than " once %d _ let lines =<< trim END let g:ScriptID = expand("<SID>") let g:Count += 1 END call setline(1, lines) let g:Count = 0 source call assert_true(g:ScriptID != '') let scid = g:ScriptID source call assert_equal(scid, g:ScriptID) call assert_equal(2, g:Count) source call assert_equal(scid, g:ScriptID) call assert_equal(3, g:Count) " test for the script line number %d _ let lines =<< trim END " comment let g:Slnum1 = expand("<slnum>") let i = 1 + \ 2 + "\ comment \ 3 let g:Slnum2 = expand("<slnum>") END call setline(1, lines) source call assert_equal('2', g:Slnum1) call assert_equal('7', g:Slnum2) " test for retaining the same script number across source calls let lines =<< trim END let g:ScriptID1 = expand("<SID>") let g:Slnum1 = expand("<slnum>") let l =<< trim END let g:Slnum2 = expand("<slnum>") let g:ScriptID2 = expand("<SID>") END new call setline(1, l) source bw! let g:ScriptID3 = expand("<SID>") let g:Slnum3 = expand("<slnum>") END call writefile(lines, 'Xscript', 'D') source Xscript call assert_true(g:ScriptID1 != g:ScriptID2) call assert_equal(g:ScriptID1, g:ScriptID3) call assert_equal('2', g:Slnum1) call assert_equal('1', g:Slnum2) call assert_equal('12', g:Slnum3) " test for sourcing a heredoc %d _ let lines =<< trim END let a = 1 let heredoc =<< trim DATA red green blue DATA let b = 2 END call setline(1, lines) source call assert_equal(['red', ' green', 'blue'], g:heredoc) " test for a while and for statement %d _ let lines =<< trim END let a = 0 let b = 1 while b <= 10 let a += 10 let b += 1 endwhile for i in range(5) let a += 10 endfor END call setline(1, lines) source call assert_equal(150, g:a) " test for sourcing the same buffer multiple times after changing a function %d _ let lines =<< trim END func Xtestfunc() return "one" endfunc END call setline(1, lines) source call assert_equal("one", Xtestfunc()) call setline(2, ' return "two"') source call assert_equal("two", Xtestfunc()) call setline(2, ' return "three"') source call assert_equal("three", Xtestfunc()) delfunc Xtestfunc " test for using try/catch %d _ let lines =<< trim END let Trace = '1' try let a1 = b1 catch let Trace ..= '2' finally let Trace ..= '3' endtry END call setline(1, lines) source call assert_equal("123", g:Trace) " test with the finish command %d _ let lines =<< trim END let g:Color = 'blue' finish let g:Color = 'green' END call setline(1, lines) source call assert_equal('blue', g:Color) " Test for the SourcePre and SourcePost autocmds augroup Xtest au! au SourcePre * let g:XsourcePre=4 \ | let g:XsourcePreFile = expand("<afile>") au SourcePost * let g:XsourcePost=6 \ | let g:XsourcePostFile = expand("<afile>") augroup END %d _ let lines =<< trim END let a = 1 END call setline(1, lines) source call assert_equal(4, g:XsourcePre) call assert_equal(6, g:XsourcePost) call assert_equal(':source buffer=' .. bufnr(), g:XsourcePreFile) call assert_equal(':source buffer=' .. bufnr(), g:XsourcePostFile) augroup Xtest au! augroup END augroup! Xtest %bw! endfunc " Test for sourcing a Vim9 script from the current buffer func Test_source_buffer_vim9() new " test for sourcing a Vim9 script %d _ let lines =<< trim END vim9script # check dict var x: number = 10 def g:Xtestfunc(): number return x enddef END call setline(1, lines) source call assert_equal(10, Xtestfunc()) " test for sourcing a vim9 script with line continuation %d _ let lines =<< trim END vim9script g:Str1 = "hello " .. "world" .. ", how are you?" g:Colors = [ 'red', # comment 'blue' ] g:Dict = { a: 22, # comment b: 33 } # calling a function with line continuation def Sum(...values: list<number>): number var sum: number = 0 for v in values sum += v endfor return sum enddef g:Total1 = Sum(10, 20, 30) var i: number = 0 while i < 10 # while loop i += 1 endwhile g:Count1 = i # for loop g:Count2 = 0 for j in range(10, 20) g:Count2 += i endfor g:Total2 = 10 + 20 - 5 g:Result1 = g:Total2 > 1 ? 'red' : 'blue' g:Str2 = 'x' ->repeat(10) ->trim() ->strpart(4) g:Result2 = g:Dict .a augroup Test au! au BufNewFile Xsubfile g:readFile = 1 | g:readExtra = 2 augroup END g:readFile = 0 g:readExtra = 0 new Xsubfile bwipe! augroup Test au! augroup END END call setline(1, lines) source call assert_equal("hello world, how are you?", g:Str1) call assert_equal(['red', 'blue'], g:Colors) call assert_equal(#{a: 22, b: 33}, g:Dict) call assert_equal(60, g:Total1) call assert_equal(10, g:Count1) call assert_equal(110, g:Count2) call assert_equal(25, g:Total2) call assert_equal('red', g:Result1) call assert_equal('xxxxxx', g:Str2) call assert_equal(22, g:Result2) call assert_equal(1, g:readFile) call assert_equal(2, g:readExtra) " test for sourcing the same buffer multiple times after changing a function %d _ let lines =<< trim END vim9script def g:Xtestfunc(): string return "one" enddef END call setline(1, lines) source call assert_equal("one", Xtestfunc()) call setline(3, ' return "two"') source call assert_equal("two", Xtestfunc()) call setline(3, ' return "three"') source call assert_equal("three", Xtestfunc()) delfunc Xtestfunc " Test for sourcing a range of lines. Make sure the script line number is " correct. %d _ let lines =<< trim END Line 1 Line 2 vim9script def g:Xtestfunc(): string return expand("<sflnum>") enddef Line 3 Line 4 END call setline(1, lines) 3,6source call assert_equal('5', Xtestfunc()) delfunc Xtestfunc " test for sourcing a heredoc %d _ let lines =<< trim END vim9script var a = 1 g:heredoc =<< trim DATA red green blue DATA var b = 2 END call setline(1, lines) source call assert_equal(['red', ' green', 'blue'], g:heredoc) " test for using the :vim9cmd modifier %d _ let lines =<< trim END first line g:Math = { pi: 3.12, e: 2.71828 } g:Editors = [ 'vim', # comment 'nano' ] last line END call setline(1, lines) vim9cmd :2,10source call assert_equal(#{pi: 3.12, e: 2.71828}, g:Math) call assert_equal(['vim', 'nano'], g:Editors) " '<,'> range before the cmd modifier works unlet g:Math unlet g:Editors exe "normal 6GV4j:vim9cmd source\<CR>" call assert_equal(['vim', 'nano'], g:Editors) unlet g:Editors " test for using try/catch %d _ let lines =<< trim END vim9script g:Trace = '1' try a1 = b1 catch g:Trace ..= '2' finally g:Trace ..= '3' endtry END call setline(1, lines) source call assert_equal('123', g:Trace) " test with the finish command %d _ let lines =<< trim END vim9script g:Color = 'red' finish g:Color = 'blue' END call setline(1, lines) source call assert_equal('red', g:Color) " test for ++clear argument to clear all the functions/variables %d _ let lines =<< trim END g:ScriptVarFound = exists("color") g:MyFuncFound = exists('*Myfunc') if g:MyFuncFound finish endif var color = 'blue' def Myfunc() enddef END call setline(1, lines) vim9cmd source call assert_false(g:MyFuncFound) call assert_false(g:ScriptVarFound) vim9cmd source call assert_true(g:MyFuncFound) call assert_true(g:ScriptVarFound) vim9cmd source ++clear call assert_false(g:MyFuncFound) call assert_false(g:ScriptVarFound) vim9cmd source ++clear call assert_false(g:MyFuncFound) call assert_false(g:ScriptVarFound) call assert_fails('vim9cmd source ++clearx', 'E475:') call assert_fails('vim9cmd source ++abcde', 'E484:') %bw! endfunc func Test_source_buffer_long_line() " This was reading past the end of the line. new norm300gr0 so bwipe! let lines =<< trim END new norm 10a0000000000ΓΈ00000000000 norm i0000000000000000000 silent! so END call writefile(lines, 'Xtest.vim', 'D') source Xtest.vim bwipe! endfunc func Test_source_buffer_with_NUL_char() " This was trying to use a line below the buffer. let lines =<< trim END if !exists('g:loaded') let g:loaded = 1 source endif END " Can't have a NL in heredoc let lines += ["silent! vim9 echo [0 \<NL> ? 'a' : 'b']"] call writefile(lines, 'XsourceNul', 'D') edit XsourceNul source bwipe! endfunc " vim: shiftwidth=2 sts=2 expandtab