From: Bram Moolenaar Date: Thu, 23 May 2019 15:38:06 +0200 Subject: patch 8.1.1366: using expressions in a modeline is unsafe Problem: Using expressions in a modeline is unsafe. Solution: Disallow using expressions in a modeline, unless the 'modelineexpr' option is set. Update help, add more tests. (cherry picked from commit 110289e78195b6d01e1e6ad26ad450de476d41c1) Signed-off-by: James McCoy --- runtime/doc/options.txt | 69 +++++++++++++++++++++++++++----- src/option.c | 35 ++++++++++------ src/option.h | 1 + src/testdir/test49.in | 2 +- src/testdir/test_modeline.vim | 93 +++++++++++++++++++++++++++++++++++++++---- src/version.c | 2 + 6 files changed, 169 insertions(+), 33 deletions(-) --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.1. Last change: 2019 Feb 03 +*options.txt* For Vim version 8.1. Last change: 2019 May 23 VIM REFERENCE MANUAL by Bram Moolenaar @@ -588,14 +588,17 @@ backslash in front of the ':' will be re /* vi:set dir=c\:\tmp: */ ~ This sets the 'dir' option to "c:\tmp". Only a single backslash before the ':' is removed. Thus to include "\:" you have to specify "\\:". - + *E992* No other commands than "set" are supported, for security reasons (somebody might create a Trojan horse text file with modelines). And not all options -can be set. For some options a flag is set, so that when it's used the -|sandbox| is effective. Still, there is always a small risk that a modeline -causes trouble. E.g., when some joker sets 'textwidth' to 5 all your lines -are wrapped unexpectedly. So disable modelines before editing untrusted text. -The mail ftplugin does this, for example. +can be set. For some options a flag is set, so that when the value is used +the |sandbox| is effective. Some options can only be set from the modeline +when 'modelineexpr' is set (the default is off). + +Still, there is always a small risk that a modeline causes trouble. E.g., +when some joker sets 'textwidth' to 5 all your lines are wrapped unexpectedly. +So disable modelines before editing untrusted text. The mail ftplugin does +this, for example. Hint: If you would like to do something else than setting an option, you could define an autocommand that checks the file for a specific string. For @@ -1189,6 +1192,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'balloonexpr' |textlock|. @@ -3354,7 +3358,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. This option can't be set from a |modeline| when the 'diff' option is - on. + on or the 'modelineexpr' option is off. It is not allowed to change text or jump to another window while evaluating 'foldexpr' |textlock|. @@ -3496,6 +3500,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'foldtext' |textlock|. @@ -3534,6 +3539,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. That stops the option from working, since changing the buffer text is not allowed. + This option cannot be set in a modeline when 'modelineexpr' is off. NOTE: This option is set to "" when 'compatible' is set. *'formatoptions'* *'fo'* @@ -3594,6 +3600,8 @@ A jump table for the options with a shor Also see 'swapsync' for controlling fsync() on swap files. 'fsync' also applies to |writefile()|, unless a flag is used to overrule it. + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. *'gdefault'* *'gd'* *'nogdefault'* *'nogd'* 'gdefault' 'gd' boolean (default off) @@ -3888,7 +3896,7 @@ A jump table for the options with a shor *'guiheadroom'* *'ghr'* 'guiheadroom' 'ghr' number (default 50) global - {not in Vi} {only for GTK and X11 GUI} + {only for GTK and X11 GUI} The number of pixels subtracted from the screen height when fitting the GUI window on the screen. Set this before the GUI is started, e.g., in your |gvimrc| file. When zero, the whole screen height will @@ -4049,6 +4057,7 @@ A jump table for the options with a shor 'guitabtooltip' is used for the tooltip, see below. The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. Only used when the GUI tab pages line is displayed. 'e' must be present in 'guioptions'. For the non-GUI tab pages line 'tabline' is @@ -4311,6 +4320,7 @@ A jump table for the options with a shor When this option contains printf-style '%' items, they will be expanded according to the rules used for 'statusline'. See 'titlestring' for example settings. + This option cannot be set in a modeline when 'modelineexpr' is off. {not available when compiled without the |+statusline| feature} *'ignorecase'* *'ic'* *'noignorecase'* *'noic'* @@ -4331,6 +4341,8 @@ A jump table for the options with a shor This option specifies a function that will be called to activate or deactivate the Input Method. It is not used in the GUI. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. Example: > function ImActivateFunc(active) @@ -4459,6 +4471,8 @@ A jump table for the options with a shor set imstatusfunc=ImStatusFunc < NOTE: This function is invoked very often. Keep it fast. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. *'imstyle'* *'imst'* 'imstyle' 'imst' number (default 1) @@ -4476,6 +4490,8 @@ A jump table for the options with a shor |single-repeat|, etc. Therefore over-the-spot style becomes the default now. This should work fine for most people, however if you have any problem with it, try using on-the-spot style. + The expression will be evaluated in the |sandbox| when set from a + modeline, see |sandbox-option|. *'include'* *'inc'* 'include' 'inc' string (default "^\s*#\s*include") @@ -4512,6 +4528,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'includeexpr' |textlock|. @@ -4601,6 +4618,7 @@ A jump table for the options with a shor The expression will be evaluated in the |sandbox| when set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'indentexpr' |textlock|. @@ -5227,6 +5245,12 @@ A jump table for the options with a shor < This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. + *'makespellmem'* *'msm'* +'makespellmem' 'msm' string (default "460000,2000,500") + global + Values relevant only when compressing a spell file, see |spell|. + This option cannot be set from a |modeline| or in the |sandbox|. + *'matchpairs'* *'mps'* 'matchpairs' 'mps' string (default "(:),{:},[:]") local to buffer @@ -5250,7 +5274,6 @@ A jump table for the options with a shor *'matchtime'* *'mat'* 'matchtime' 'mat' number (default 5) global - {not in Vi}{in Nvi} Tenths of a second to show the matching paren, when 'showmatch' is set. Note that this is not in milliseconds, like other options that set a time. This is to be compatible with Nvi. @@ -5394,6 +5417,17 @@ A jump table for the options with a shor 'modeline' 'ml' boolean (Vim default: on (off for root), Debian: off, Vi default: off) local to buffer + If 'modeline' is on 'modelines' gives the number of lines that is + checked for set commands. If 'modeline' is off or 'modelines' is zero + no lines are checked. See |modeline|. + + *'modelineexpr'* *'mle'* *'nomodelineexpr'* *'nomle'* +'modelineexpr' 'mle' boolean (default: off) + global + When on allow some options that are an expression to be set in the + modeline. Check the option for whether it is affected by + 'modelineexpr'. Also see |modeline|. + *'modelines'* *'mls'* 'modelines' 'mls' number (default 5) global @@ -5405,9 +5439,9 @@ A jump table for the options with a shor set and to the Vim default value when 'compatible' is reset. *'modifiable'* *'ma'* *'nomodifiable'* *'noma'* + *E21* 'modifiable' 'ma' boolean (default on) local to buffer - {not in Vi} *E21* When off the buffer contents cannot be changed. The 'fileformat' and 'fileencoding' options also can't be changed. Can be reset on startup with the |-M| command line argument. @@ -6456,6 +6490,8 @@ A jump table for the options with a shor When this option is not empty, it determines the content of the ruler string, as displayed for the 'ruler' option. The format of this option is like that of 'statusline'. + This option cannot be set in a modeline when 'modelineexpr' is off. + The default ruler width is 17 characters. To make the ruler 15 characters wide, put "%15(" at the start and "%)" at the end. Example: > @@ -7016,6 +7052,8 @@ A jump table for the options with a shor q use "recording" instead of "recording @a" F don't give the file info when editing a file, like `:silent` was used for the command + was used for the command; note that this also affects messages + from autocommands This gives you the opportunity to avoid that a change between buffers requires you to hit , but still gives as useful a message as @@ -7600,6 +7638,7 @@ A jump table for the options with a shor The 'statusline' option will be evaluated in the |sandbox| if set from a modeline, see |sandbox-option|. + This option cannot be set in a modeline when 'modelineexpr' is off. It is not allowed to change text or jump to another window while evaluating 'statusline' |textlock|. @@ -7786,6 +7825,7 @@ A jump table for the options with a shor When changing something that is used in 'tabline' that does not trigger it to be updated, use |:redrawtabline|. + This option cannot be set in a modeline when 'modelineexpr' is off. Keep in mind that only one of the tab pages is the current one, others are invisible and you can't jump to their windows. @@ -8329,8 +8369,11 @@ A jump table for the options with a shor non-empty 't_ts' option). When Vim was compiled with HAVE_X11 defined, the original title will be restored if possible, see |X11|. + When this option contains printf-style '%' items, they will be expanded according to the rules used for 'statusline'. + This option cannot be set in a modeline when 'modelineexpr' is off. + Example: > :auto BufEnter * let &titlestring = hostname() . "/" . expand("%:p") :set title titlestring=%<%F%=%l/%L-%P titlelen=70 @@ -8520,6 +8563,8 @@ A jump table for the options with a shor undo file that exists is used. When it cannot be read an error is given, no further entry is used. See |undo-persistence|. + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. *'undofile'* *'noundofile'* *'udf'* *'noudf'* 'undofile' 'udf' boolean (default off) @@ -8843,6 +8888,8 @@ A jump table for the options with a shor When equal to "NONE" no viminfo file will be read or written. This option can be set with the |-i| command line flag. The |--clean| command line flag sets it to "NONE". + This option cannot be set from a |modeline| or in the |sandbox|, for + security reasons. *'virtualedit'* *'ve'* 'virtualedit' 've' string (default "") --- a/src/option.c +++ b/src/option.c @@ -462,6 +462,7 @@ struct vimoption * there is a redraw flag */ #define P_NDNAME 0x8000000L /* only normal dir name chars allowed */ #define P_RWINONLY 0x10000000L /* only redraw current window */ +#define P_MLE 0x20000000L /* under control of 'modelineexpr' */ #define ISK_LATIN1 (char_u *)"@,48-57,_,192-255" @@ -649,7 +650,7 @@ static struct vimoption options[] = {(char_u *)0L, (char_u *)0L} #endif SCTX_INIT}, - {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, + {"balloonexpr", "bexpr", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, #if defined(FEAT_BEVAL) && defined(FEAT_EVAL) (char_u *)&p_bexpr, PV_BEXPR, {(char_u *)"", (char_u *)0L} @@ -726,7 +727,7 @@ static struct vimoption options[] = (char_u *)&p_cmp, PV_NONE, {(char_u *)"internal,keepascii", (char_u *)0L} SCTX_INIT}, - {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_COMMA|P_NODUP, + {"cdpath", "cd", P_STRING|P_EXPAND|P_VI_DEF|P_SECURE|P_COMMA|P_NODUP, #ifdef FEAT_SEARCHPATH (char_u *)&p_cdpath, PV_NONE, {(char_u *)",,", (char_u *)0L} @@ -1178,7 +1179,7 @@ static struct vimoption options[] = {(char_u *)NULL, (char_u *)0L} #endif SCTX_INIT}, - {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN, + {"foldexpr", "fde", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE, #if defined(FEAT_FOLDING) && defined(FEAT_EVAL) (char_u *)VAR_WIN, PV_FDE, {(char_u *)"0", (char_u *)NULL} @@ -1261,7 +1262,7 @@ static struct vimoption options[] = {(char_u *)NULL, (char_u *)0L} #endif SCTX_INIT}, - {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN, + {"foldtext", "fdt", P_STRING|P_ALLOCED|P_VIM|P_VI_DEF|P_RWIN|P_MLE, #if defined(FEAT_FOLDING) && defined(FEAT_EVAL) (char_u *)VAR_WIN, PV_FDT, {(char_u *)"foldtext()", (char_u *)NULL} @@ -1270,7 +1271,7 @@ static struct vimoption options[] = {(char_u *)NULL, (char_u *)0L} #endif SCTX_INIT}, - {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, + {"formatexpr", "fex", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, #ifdef FEAT_EVAL (char_u *)&p_fex, PV_FEX, {(char_u *)"", (char_u *)0L} @@ -1409,7 +1410,7 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)TRUE, (char_u *)0L} SCTX_INIT}, - {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN, + {"guitablabel", "gtl", P_STRING|P_VI_DEF|P_RWIN|P_MLE, #if defined(FEAT_GUI_TABLINE) (char_u *)&p_gtl, PV_NONE, {(char_u *)"", (char_u *)0L} @@ -1480,7 +1481,7 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, - {"iconstring", NULL, P_STRING|P_VI_DEF, + {"iconstring", NULL, P_STRING|P_VI_DEF|P_MLE, #ifdef FEAT_TITLE (char_u *)&p_iconstring, PV_NONE, #else @@ -1552,7 +1553,7 @@ static struct vimoption options[] = {(char_u *)0L, (char_u *)0L} #endif SCTX_INIT}, - {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF, + {"includeexpr", "inex", P_STRING|P_ALLOCED|P_VI_DEF|P_MLE, #if defined(FEAT_FIND_ID) && defined(FEAT_EVAL) (char_u *)&p_inex, PV_INEX, {(char_u *)"", (char_u *)0L} @@ -1564,7 +1565,7 @@ static struct vimoption options[] = {"incsearch", "is", P_BOOL|P_VI_DEF|P_VIM, (char_u *)&p_is, PV_NONE, {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, - {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM, + {"indentexpr", "inde", P_STRING|P_ALLOCED|P_VI_DEF|P_VIM|P_MLE, #if defined(FEAT_CINDENT) && defined(FEAT_EVAL) (char_u *)&p_inde, PV_INDE, {(char_u *)"", (char_u *)0L} @@ -1891,6 +1892,9 @@ static struct vimoption options[] = {"modeline", "ml", P_BOOL|P_VIM, (char_u *)&p_ml, PV_ML, {(char_u *)FALSE, (char_u *)TRUE} SCTX_INIT}, + {"modelineexpr", "mle", P_BOOL|P_VI_DEF, + (char_u *)&p_mle, PV_NONE, + {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, {"modelines", "mls", P_NUM|P_VI_DEF, (char_u *)&p_mls, PV_NONE, {(char_u *)5L, (char_u *)0L} SCTX_INIT}, @@ -2314,7 +2318,7 @@ static struct vimoption options[] = (char_u *)NULL, PV_NONE, #endif {(char_u *)FALSE, (char_u *)0L} SCTX_INIT}, - {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT, + {"rulerformat", "ruf", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE, #ifdef FEAT_STL_OPT (char_u *)&p_ruf, PV_NONE, #else @@ -2580,7 +2584,7 @@ static struct vimoption options[] = {"startofline", "sol", P_BOOL|P_VI_DEF|P_VIM, (char_u *)&p_sol, PV_NONE, {(char_u *)TRUE, (char_u *)0L} SCTX_INIT}, - {"statusline" ,"stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT, + {"statusline" ,"stl", P_STRING|P_VI_DEF|P_ALLOCED|P_RSTAT|P_MLE, #ifdef FEAT_STL_OPT (char_u *)&p_stl, PV_STL, #else @@ -2627,7 +2631,7 @@ static struct vimoption options[] = {(char_u *)0L, (char_u *)0L} #endif SCTX_INIT}, - {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL, + {"tabline", "tal", P_STRING|P_VI_DEF|P_RALL|P_MLE, #ifdef FEAT_STL_OPT (char_u *)&p_tal, PV_NONE, #else @@ -2796,7 +2800,7 @@ static struct vimoption options[] = {(char_u *)0L, (char_u *)0L} #endif SCTX_INIT}, - {"titlestring", NULL, P_STRING|P_VI_DEF, + {"titlestring", NULL, P_STRING|P_VI_DEF|P_MLE, #ifdef FEAT_TITLE (char_u *)&p_titlestring, PV_NONE, #else @@ -4542,6 +4546,11 @@ do_set( errmsg = _("E520: Not allowed in a modeline"); goto skip; } + if ((flags & P_MLE) && !p_mle) + { + errmsg = _("E992: Not allowed in a modeline when 'modelineexpr' is off"); + goto skip; + } #ifdef FEAT_DIFF /* In diff mode some options are overruled. This avoids that * 'foldmethod' becomes "marker" instead of "diff" and that --- a/src/option.h +++ b/src/option.h @@ -640,6 +640,7 @@ EXTERN long p_mis; /* 'menuitems' */ #ifdef FEAT_SPELL EXTERN char_u *p_msm; /* 'mkspellmem' */ #endif +EXTERN long p_mle; /* 'modelineexpr' */ EXTERN long p_mls; /* 'modelines' */ EXTERN char_u *p_mouse; /* 'mouse' */ #ifdef FEAT_GUI --- a/src/testdir/test49.in +++ b/src/testdir/test49.in @@ -5,7 +5,7 @@ test49.failed, try to add one or more "G STARTTEST :so small.vim -:se nocp nomore viminfo+=nviminfo +:se nocp nomore viminfo+=nviminfo modelineexpr :lang mess C :so test49.vim :" Go back to this file and append the results from register r. --- a/src/testdir/test_modeline.vim +++ b/src/testdir/test_modeline.vim @@ -60,14 +60,17 @@ func Test_modeline_keymap() set keymap= iminsert=0 imsearch=-1 endfunc -func s:modeline_fails(what, text) +func s:modeline_fails(what, text, error) + if !exists('+' . a:what) + return + endif let fname = "Xmodeline_fails_" . a:what call writefile(['vim: set ' . a:text . ' :', 'nothing'], fname) let modeline = &modeline set modeline filetype plugin on syntax enable - call assert_fails('split ' . fname, 'E474:') + call assert_fails('split ' . fname, a:error) call assert_equal("", &filetype) call assert_equal("", &syntax) @@ -79,16 +82,90 @@ func s:modeline_fails(what, text) endfunc func Test_modeline_filetype_fails() - call s:modeline_fails('filetype', 'ft=evil$CMD') + call s:modeline_fails('filetype', 'ft=evil$CMD', 'E474:') endfunc func Test_modeline_syntax_fails() - call s:modeline_fails('syntax', 'syn=evil$CMD') + call s:modeline_fails('syntax', 'syn=evil$CMD', 'E474:') endfunc func Test_modeline_keymap_fails() - if !has('keymap') - return - endif - call s:modeline_fails('keymap', 'keymap=evil$CMD') + call s:modeline_fails('keymap', 'keymap=evil$CMD', 'E474:') +endfunc + +func Test_modeline_fails_always() + call s:modeline_fails('backupdir', 'backupdir=Something()', 'E520:') + call s:modeline_fails('cdpath', 'cdpath=Something()', 'E520:') + call s:modeline_fails('charconvert', 'charconvert=Something()', 'E520:') + call s:modeline_fails('completefunc', 'completefunc=Something()', 'E520:') + call s:modeline_fails('cscopeprg', 'cscopeprg=Something()', 'E520:') + call s:modeline_fails('diffexpr', 'diffexpr=Something()', 'E520:') + call s:modeline_fails('directory', 'directory=Something()', 'E520:') + call s:modeline_fails('equalprg', 'equalprg=Something()', 'E520:') + call s:modeline_fails('errorfile', 'errorfile=Something()', 'E520:') + call s:modeline_fails('exrc', 'exrc=Something()', 'E520:') + call s:modeline_fails('formatprg', 'formatprg=Something()', 'E520:') + call s:modeline_fails('fsync', 'fsync=Something()', 'E520:') + call s:modeline_fails('grepprg', 'grepprg=Something()', 'E520:') + call s:modeline_fails('helpfile', 'helpfile=Something()', 'E520:') + call s:modeline_fails('imactivatefunc', 'imactivatefunc=Something()', 'E520:') + call s:modeline_fails('imstatusfunc', 'imstatusfunc=Something()', 'E520:') + call s:modeline_fails('imstyle', 'imstyle=Something()', 'E520:') + call s:modeline_fails('keywordprg', 'keywordprg=Something()', 'E520:') + call s:modeline_fails('langmap', 'langmap=Something()', 'E520:') + call s:modeline_fails('luadll', 'luadll=Something()', 'E520:') + call s:modeline_fails('makeef', 'makeef=Something()', 'E520:') + call s:modeline_fails('makeprg', 'makeprg=Something()', 'E520:') + call s:modeline_fails('makespellmem', 'makespellmem=Something()', 'E520:') + call s:modeline_fails('mzschemedll', 'mzschemedll=Something()', 'E520:') + call s:modeline_fails('mzschemegcdll', 'mzschemegcdll=Something()', 'E520:') + call s:modeline_fails('omnifunc', 'omnifunc=Something()', 'E520:') + call s:modeline_fails('operatorfunc', 'operatorfunc=Something()', 'E520:') + call s:modeline_fails('perldll', 'perldll=Something()', 'E520:') + call s:modeline_fails('printdevice', 'printdevice=Something()', 'E520:') + call s:modeline_fails('patchexpr', 'patchexpr=Something()', 'E520:') + call s:modeline_fails('printexpr', 'printexpr=Something()', 'E520:') + call s:modeline_fails('pythondll', 'pythondll=Something()', 'E520:') + call s:modeline_fails('pythonhome', 'pythondll=Something()', 'E520:') + call s:modeline_fails('pythonthreedll', 'pythonthreedll=Something()', 'E520:') + call s:modeline_fails('pythonthreehome', 'pythonthreehome=Something()', 'E520:') + call s:modeline_fails('pyxversion', 'pyxversion=Something()', 'E520:') + call s:modeline_fails('rubydll', 'rubydll=Something()', 'E520:') + call s:modeline_fails('runtimepath', 'runtimepath=Something()', 'E520:') + call s:modeline_fails('secure', 'secure=Something()', 'E520:') + call s:modeline_fails('shell', 'shell=Something()', 'E520:') + call s:modeline_fails('shellcmdflag', 'shellcmdflag=Something()', 'E520:') + call s:modeline_fails('shellpipe', 'shellpipe=Something()', 'E520:') + call s:modeline_fails('shellquote', 'shellquote=Something()', 'E520:') + call s:modeline_fails('shellredir', 'shellredir=Something()', 'E520:') + call s:modeline_fails('shellxquote', 'shellxquote=Something()', 'E520:') + call s:modeline_fails('spellfile', 'spellfile=Something()', 'E520:') + call s:modeline_fails('spellsuggest', 'spellsuggest=Something()', 'E520:') + call s:modeline_fails('tcldll', 'tcldll=Something()', 'E520:') + call s:modeline_fails('titleold', 'titleold=Something()', 'E520:') + call s:modeline_fails('viewdir', 'viewdir=Something()', 'E520:') + call s:modeline_fails('viminfo', 'viminfo=Something()', 'E520:') + call s:modeline_fails('viminfofile', 'viminfofile=Something()', 'E520:') + call s:modeline_fails('winptydll', 'winptydll=Something()', 'E520:') + call s:modeline_fails('undodir', 'undodir=Something()', 'E520:') + " only check a few terminal options + call s:modeline_fails('t_AB', 't_AB=Something()', 'E520:') + call s:modeline_fails('t_ce', 't_ce=Something()', 'E520:') + call s:modeline_fails('t_sr', 't_sr=Something()', 'E520:') + call s:modeline_fails('t_8b', 't_8b=Something()', 'E520:') +endfunc + +func Test_modeline_fails_modelineexpr() + call s:modeline_fails('balloonexpr', 'balloonexpr=Something()', 'E992:') + call s:modeline_fails('foldexpr', 'foldexpr=Something()', 'E992:') + call s:modeline_fails('foldtext', 'foldtext=Something()', 'E992:') + call s:modeline_fails('formatexpr', 'formatexpr=Something()', 'E992:') + call s:modeline_fails('guitablabel', 'guitablabel=Something()', 'E992:') + call s:modeline_fails('iconstring', 'iconstring=Something()', 'E992:') + call s:modeline_fails('includeexpr', 'includeexpr=Something()', 'E992:') + call s:modeline_fails('indentexpr', 'indentexpr=Something()', 'E992:') + call s:modeline_fails('rulerformat', 'rulerformat=Something()', 'E992:') + call s:modeline_fails('statusline', 'statusline=Something()', 'E992:') + call s:modeline_fails('tabline', 'tabline=Something()', 'E992:') + call s:modeline_fails('titlestring', 'titlestring=Something()', 'E992:') endfunc --- a/src/version.c +++ b/src/version.c @@ -792,6 +792,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1366, +/**/ 1365, /**/ 1046,