diff --git a/src/beval.c b/src/beval.c index 65dfbc2aad..0b397b6440 100644 --- a/src/beval.c +++ b/src/beval.c @@ -235,7 +235,6 @@ bexpr_eval( { win_T *cw; long winnr = 0; - buf_T *save_curbuf; int use_sandbox; static char_u *result = NULL; size_t len; @@ -254,15 +253,8 @@ bexpr_eval( set_vim_var_string(VV_BEVAL_TEXT, text, -1); vim_free(text); - /* - * Temporarily change the curbuf, so that we can determine whether - * the buffer-local balloonexpr option was set insecurely. - */ - save_curbuf = curbuf; - curbuf = wp->w_buffer; - use_sandbox = was_set_insecurely((char_u *)"balloonexpr", - *curbuf->b_p_bexpr == NUL ? 0 : OPT_LOCAL); - curbuf = save_curbuf; + use_sandbox = was_set_insecurely(wp, (char_u *)"balloonexpr", + *wp->w_buffer->b_p_bexpr == NUL ? 0 : OPT_LOCAL); if (use_sandbox) ++sandbox; ++textlock; diff --git a/src/buffer.c b/src/buffer.c index 29908c4aa8..0c21d196f6 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -4423,7 +4423,7 @@ build_stl_str_hl( #ifdef FEAT_EVAL // if "fmt" was set insecurely it needs to be evaluated in the sandbox - use_sandbox = was_set_insecurely(opt_name, opt_scope); + use_sandbox = was_set_insecurely(wp, opt_name, opt_scope); // When the format starts with "%!" then evaluate it as an expression and // use the result as the actual format string. diff --git a/src/eval.c b/src/eval.c index 4a55adac72..1b522d37c4 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1020,7 +1020,7 @@ eval_foldexpr(win_T *wp, int *cp) varnumber_T retval; char_u *s; sctx_T saved_sctx = current_sctx; - int use_sandbox = was_set_insecurely((char_u *)"foldexpr", + int use_sandbox = was_set_insecurely(wp, (char_u *)"foldexpr", OPT_LOCAL); arg = skipwhite(wp->w_p_fde); diff --git a/src/findfile.c b/src/findfile.c index c0418d51c3..cd2f85b67f 100644 --- a/src/findfile.c +++ b/src/findfile.c @@ -2186,7 +2186,7 @@ eval_includeexpr(char_u *ptr, int len) current_sctx = curbuf->b_p_script_ctx[BV_INEX]; res = eval_to_string_safe(curbuf->b_p_inex, - was_set_insecurely((char_u *)"includeexpr", OPT_LOCAL), + was_set_insecurely(curwin, (char_u *)"includeexpr", OPT_LOCAL), TRUE, TRUE); set_vim_var_string(VV_FNAME, NULL, 0); diff --git a/src/fold.c b/src/fold.c index 4824a807ce..e5b49f6743 100644 --- a/src/fold.c +++ b/src/fold.c @@ -1965,8 +1965,8 @@ get_foldtext( ++emsg_off; // handle exceptions, but don't display errors text = eval_to_string_safe(wp->w_p_fdt, - was_set_insecurely((char_u *)"foldtext", OPT_LOCAL), - TRUE, TRUE); + was_set_insecurely(wp, (char_u *)"foldtext", OPT_LOCAL), + TRUE, TRUE); --emsg_off; if (text == NULL || did_emsg) diff --git a/src/indent.c b/src/indent.c index 4e2614943c..320d4a2328 100644 --- a/src/indent.c +++ b/src/indent.c @@ -1958,8 +1958,8 @@ get_expr_indent(void) colnr_T save_curswant; int save_set_curswant; int save_State; - int use_sandbox = was_set_insecurely((char_u *)"indentexpr", - OPT_LOCAL); + int use_sandbox = was_set_insecurely(curwin, + (char_u *)"indentexpr", OPT_LOCAL); sctx_T save_sctx = current_sctx; // Save and restore cursor position and curswant, in case it was changed diff --git a/src/option.c b/src/option.c index 8a495e087a..bfdaa7ec51 100644 --- a/src/option.c +++ b/src/option.c @@ -46,9 +46,9 @@ static char_u *option_expand(int opt_idx, char_u *val); static void didset_options(void); static void didset_options2(void); #if defined(FEAT_EVAL) || defined(PROTO) -static long_u *insecure_flag(int opt_idx, int opt_flags); +static long_u *insecure_flag(win_T *wp, int opt_idx, int opt_flags); #else -# define insecure_flag(opt_idx, opt_flags) (&options[opt_idx].flags) +# define insecure_flag(wp, opt_idx, opt_flags) (&options[opt_idx].flags) #endif static char *set_bool_option(int opt_idx, char_u *varp, int value, int opt_flags); static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf, size_t errbuflen, int opt_flags); @@ -829,11 +829,11 @@ set_option_default( } // The default value is not insecure. - flagsp = insecure_flag(opt_idx, opt_flags); + flagsp = insecure_flag(curwin, opt_idx, opt_flags); *flagsp = *flagsp & ~P_INSECURE; if (both) { - flagsp = insecure_flag(opt_idx, OPT_LOCAL); + flagsp = insecure_flag(curwin, opt_idx, OPT_LOCAL); *flagsp = *flagsp & ~P_INSECURE; } } @@ -2140,7 +2140,7 @@ do_set_option_string( #endif { - long_u *p = insecure_flag(opt_idx, opt_flags); + long_u *p = insecure_flag(curwin, opt_idx, opt_flags); int secure_saved = secure; // When an option is set in the sandbox, from a modeline or in secure @@ -2795,9 +2795,9 @@ did_set_option( // When an option is set in the sandbox, from a modeline or in secure mode // set the P_INSECURE flag. Otherwise, if a new value is stored reset the // flag. - flagsp = insecure_flag(opt_idx, opt_flags); + flagsp = insecure_flag(curwin, opt_idx, opt_flags); if (both) - flagsp_local = insecure_flag(opt_idx, OPT_LOCAL); + flagsp_local = insecure_flag(curwin, opt_idx, OPT_LOCAL); if (!value_checked && (secure #ifdef HAVE_SANDBOX || sandbox != 0 @@ -3072,14 +3072,14 @@ set_term_option_alloced(char_u **p) * Return -1 for an unknown option. */ int -was_set_insecurely(char_u *opt, int opt_flags) +was_set_insecurely(win_T *wp, char_u *opt, int opt_flags) { int idx = findoption(opt); long_u *flagp; if (idx >= 0) { - flagp = insecure_flag(idx, opt_flags); + flagp = insecure_flag(wp, idx, opt_flags); return (*flagp & P_INSECURE) != 0; } internal_error("was_set_insecurely()"); @@ -3093,28 +3093,38 @@ was_set_insecurely(char_u *opt, int opt_flags) * the option is used. */ static long_u * -insecure_flag(int opt_idx, int opt_flags) +insecure_flag(win_T *wp, int opt_idx, int opt_flags) { if (opt_flags & OPT_LOCAL) switch ((int)options[opt_idx].indir) { - case PV_WRAP: return &curwin->w_p_wrap_flags; + case PV_WRAP: return &wp->w_p_wrap_flags; #ifdef FEAT_STL_OPT - case PV_STL: return &curwin->w_p_stl_flags; + case PV_STL: return &wp->w_p_stl_flags; #endif #ifdef FEAT_EVAL # ifdef FEAT_FOLDING - case PV_FDE: return &curwin->w_p_fde_flags; - case PV_FDT: return &curwin->w_p_fdt_flags; + case PV_FDE: return &wp->w_p_fde_flags; + case PV_FDT: return &wp->w_p_fdt_flags; # endif # ifdef FEAT_BEVAL - case PV_BEXPR: return &curbuf->b_p_bexpr_flags; + case PV_BEXPR: return &wp->w_buffer->b_p_bexpr_flags; # endif - case PV_INDE: return &curbuf->b_p_inde_flags; - case PV_FEX: return &curbuf->b_p_fex_flags; + case PV_INDE: return &wp->w_buffer->b_p_inde_flags; + case PV_FEX: return &wp->w_buffer->b_p_fex_flags; # ifdef FEAT_FIND_ID - case PV_INEX: return &curbuf->b_p_inex_flags; + case PV_INEX: return &wp->w_buffer->b_p_inex_flags; # endif +#endif + } + else + // For global value of window-local options, use flags in w_allbuf_opt. + switch ((int)options[opt_idx].indir) + { + case PV_WRAP: return &wp->w_allbuf_opt.wo_wrap_flags; +#if defined(FEAT_EVAL) && defined(FEAT_FOLDING) + case PV_FDE: return &wp->w_allbuf_opt.wo_fde_flags; + case PV_FDT: return &wp->w_allbuf_opt.wo_fdt_flags; #endif } @@ -7141,6 +7151,15 @@ copy_winopt(winopt_T *from, winopt_T *to) to->wo_lhi = from->wo_lhi; #endif + to->wo_wrap_flags = from->wo_wrap_flags; +#ifdef FEAT_STL_OPT + to->wo_stl_flags = from->wo_stl_flags; +#endif +#ifdef FEAT_EVAL + to->wo_fde_flags = from->wo_fde_flags; + to->wo_fdt_flags = from->wo_fdt_flags; +#endif + #ifdef FEAT_EVAL // Copy the script context so that we know where the value was last set. mch_memmove(to->wo_script_ctx, from->wo_script_ctx, diff --git a/src/proto/option.pro b/src/proto/option.pro index de551d83ec..4fa8935c0f 100644 --- a/src/proto/option.pro +++ b/src/proto/option.pro @@ -18,7 +18,7 @@ void set_options_bin(int oldval, int newval, int opt_flags); void check_options(void); int get_term_opt_idx(char_u **p); int set_term_option_alloced(char_u **p); -int was_set_insecurely(char_u *opt, int opt_flags); +int was_set_insecurely(win_T *wp, char_u *opt, int opt_flags); void redraw_titles(void); int valid_name(char_u *val, char *allowed); void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx); diff --git a/src/structs.h b/src/structs.h index fd752109f5..f39f5d3a64 100644 --- a/src/structs.h +++ b/src/structs.h @@ -348,6 +348,20 @@ typedef struct # define w_p_twk w_onebuf_opt.wo_twk // 'termwinkey' char_u *wo_tws; # define w_p_tws w_onebuf_opt.wo_tws // 'termwinsize' +#endif + + // A few options have local flags for P_INSECURE. + long_u wo_wrap_flags; // flags for 'wrap' +#define w_p_wrap_flags w_onebuf_opt.wo_wrap_flags +#ifdef FEAT_STL_OPT + long_u wo_stl_flags; // flags for 'statusline' +# define w_p_stl_flags w_onebuf_opt.wo_stl_flags +#endif +#ifdef FEAT_EVAL + long_u wo_fde_flags; // flags for 'foldexpr' +# define w_p_fde_flags w_onebuf_opt.wo_fde_flags + long_u wo_fdt_flags; // flags for 'foldtext' +# define w_p_fdt_flags w_onebuf_opt.wo_fdt_flags #endif #ifdef FEAT_EVAL @@ -4213,15 +4227,6 @@ struct window_S // transform a pointer to a "onebuf" option into a "allbuf" option #define GLOBAL_WO(p) ((char *)(p) + sizeof(winopt_T)) - // A few options have local flags for P_INSECURE. - long_u w_p_wrap_flags; // flags for 'wrap' -#ifdef FEAT_STL_OPT - long_u w_p_stl_flags; // flags for 'statusline' -#endif -#ifdef FEAT_EVAL - long_u w_p_fde_flags; // flags for 'foldexpr' - long_u w_p_fdt_flags; // flags for 'foldtext' -#endif #if defined(FEAT_SIGNS) || defined(FEAT_FOLDING) || defined(FEAT_DIFF) int *w_p_cc_cols; // array of columns to highlight or NULL char_u w_p_culopt_flags; // flags for cursorline highlighting diff --git a/src/tabpanel.c b/src/tabpanel.c index f393fafca2..35c0ccab7b 100644 --- a/src/tabpanel.c +++ b/src/tabpanel.c @@ -465,7 +465,7 @@ starts_with_percent_and_bang(tabpanel_T *pargs) #ifdef FEAT_EVAL // if "fmt" was set insecurely it needs to be evaluated in the sandbox - int use_sandbox = was_set_insecurely(opt_name, opt_scope); + int use_sandbox = was_set_insecurely(curwin, opt_name, opt_scope); // When the format starts with "%!" then evaluate it as an expression and // use the result as the actual format string. diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim index 3a00d9c2cd..5ba2e81f34 100644 --- a/src/testdir/test_fold.vim +++ b/src/testdir/test_fold.vim @@ -1688,6 +1688,11 @@ func Test_foldtext_in_modeline() call assert_equal('folded text', foldtextresult(1)) call assert_equal(['before'], readfile('Xmodelinefoldtext_write')) + split + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(['before'], readfile('Xmodelinefoldtext_write')) + close + setglobal foldtext=ModelineFoldText() call assert_equal('folded text', foldtextresult(1)) call assert_equal(['before'], readfile('Xmodelinefoldtext_write')) @@ -1715,6 +1720,28 @@ func Test_foldtext_in_modeline() call Check_foldtext_in_modeline('setlocal') call Check_foldtext_in_modeline('set') + new Xa + sandbox setglobal foldenable foldtext=ModelineFoldText() + setlocal bufhidden=wipe + call writefile(['before'], 'Xmodelinefoldtext_write', 'D') + edit! Xb + call setline(1, ['func T()', ' let i = 1', 'endfunc']) | %fold + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(['before'], readfile('Xmodelinefoldtext_write')) + setglobal foldtext=ModelineFoldText() + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(['before'], readfile('Xmodelinefoldtext_write')) + setlocal foldtext=ModelineFoldText() + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(['after'], readfile('Xmodelinefoldtext_write')) + setlocal bufhidden=wipe + call writefile(['before'], 'Xmodelinefoldtext_write', 'D') + edit! Xc + call setline(1, ['func T()', ' let i = 1', 'endfunc']) | %fold + call assert_equal('folded text', foldtextresult(1)) + call assert_equal(['after'], readfile('Xmodelinefoldtext_write')) + bwipe! + set modeline& modelineexpr& delfunc ModelineFoldText delfunc Check_foldtext_in_modeline @@ -1744,6 +1771,11 @@ func Test_foldexpr_in_modeline() call assert_equal(2, foldlevel(3)) call assert_equal(['before'], readfile('Xmodelinefoldexpr_write')) + split + call assert_equal(2, foldlevel(3)) + call assert_equal(['before'], readfile('Xmodelinefoldexpr_write')) + close + setglobal foldexpr=ModelineFoldExpr() call assert_equal(2, foldlevel(3)) call assert_equal(['before'], readfile('Xmodelinefoldexpr_write')) @@ -1771,6 +1803,28 @@ func Test_foldexpr_in_modeline() call Check_foldexpr_in_modeline('setlocal') call Check_foldexpr_in_modeline('set') + new Xa + sandbox setglobal foldenable foldmethod=expr foldexpr=ModelineFoldExpr() + setlocal bufhidden=wipe + call writefile(['before'], 'Xmodelinefoldexpr_write', 'D') + edit! Xb + call setline(1, lines[0:5]) + call assert_equal(2, foldlevel(3)) + call assert_equal(['before'], readfile('Xmodelinefoldexpr_write')) + setglobal foldexpr=ModelineFoldExpr() + call assert_equal(2, foldlevel(3)) + call assert_equal(['before'], readfile('Xmodelinefoldexpr_write')) + setlocal foldexpr=ModelineFoldExpr() + call assert_equal(2, foldlevel(3)) + call assert_equal(['after'], readfile('Xmodelinefoldexpr_write')) + setlocal bufhidden=wipe + call writefile(['before'], 'Xmodelinefoldexpr_write', 'D') + edit! Xc + call setline(1, lines[0:5]) + call assert_equal(2, foldlevel(3)) + call assert_equal(['after'], readfile('Xmodelinefoldexpr_write')) + bwipe! + set modeline& modelineexpr& delfunc ModelineFoldExpr delfunc Check_foldexpr_in_modeline diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim index cb144c580a..4cc091b9ca 100644 --- a/src/testdir/test_modeline.vim +++ b/src/testdir/test_modeline.vim @@ -369,19 +369,35 @@ func Test_modeline_nowrap_lcs_extends() \ 'ccc evil', \ 'ddd vim: nowrap', \ ], 'Xmodeline_nowrap', 'D') - call NewWindow(10, 20) + set noequalalways + 11new | 20vsplit func Check_modeline_nowrap(expect_insecure, expect_secure, set_cmd) edit Xmodeline_nowrap call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) + + 5split + call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) + call assert_equal(a:expect_insecure, ScreenLines([7, 11], 20)) + + exe a:set_cmd 'nowrap' + call assert_equal(a:expect_secure, ScreenLines([1, 5], 20)) + call assert_equal(a:expect_insecure, ScreenLines([7, 11], 20)) + + close + call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) + setglobal nowrap call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) setglobal wrap call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) + exe a:set_cmd 'nowrap' call assert_equal(a:expect_secure, ScreenLines([1, 5], 20)) + exe 'sandbox' a:set_cmd 'nowrap' call assert_equal(a:expect_insecure, ScreenLines([1, 5], 20)) + exe a:set_cmd 'nowrap' call assert_equal(a:expect_secure, ScreenLines([1, 5], 20)) endfunc @@ -450,8 +466,28 @@ func Test_modeline_nowrap_lcs_extends() call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal') call Check_modeline_nowrap(expect_insecure, expect_secure, 'set') - call CloseWindow() + sandbox setglobal nowrap + setglobal list listchars=eol:$ + setlocal bufhidden=wipe + enew! + call setline(1, ['aaa bbb']) + call assert_equal(['aaa >'], ScreenLines(1, 20)) + setglobal nowrap + call assert_equal(['aaa >'], ScreenLines(1, 20)) + setlocal nowrap + call assert_equal(['aaa '], ScreenLines(1, 20)) + normal! 20zl + call assert_equal([' bbb$ '], ScreenLines(1, 20)) + setlocal bufhidden=wipe + enew! + call setline(1, ['ccc ddd']) + call assert_equal(['ccc '], ScreenLines(1, 20)) + normal! 20zl + call assert_equal([' ddd$ '], ScreenLines(1, 20)) + + bwipe! delfunc Check_modeline_nowrap + set equalalways& endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim index e1f6359401..9aa6aef664 100644 --- a/src/testdir/test_statusline.vim +++ b/src/testdir/test_statusline.vim @@ -645,17 +645,31 @@ func Test_statusline_in_sandbox() endfunc func Check_statusline_in_sandbox(set_cmd0, set_cmd1) - new | only - call writefile(['before'], 'Xsandboxstatusline_write', 'D') + only + 11new | 20vsplit + call setline(1, 'foo') + windo setlocal statusline=SomethingElse + wincmd t setlocal statusline= + call writefile(['before'], 'Xsandboxstatusline_write', 'D') + exe 'sandbox' a:set_cmd0 'statusline=%!SandboxStatusLine()' call assert_equal('', &l:statusline) sandbox setlocal statusline=%!SandboxStatusLine() call assert_fails('redrawstatus', 'E48:') call assert_equal(['before'], readfile('Xsandboxstatusline_write')) + wincmd b + call assert_fails('redrawstatus!', 'E48:') + call assert_equal(['before'], readfile('Xsandboxstatusline_write')) + wincmd t + + 5split + call assert_fails('redrawstatus!', 'E48:') + call assert_equal(['before'], readfile('Xsandboxstatusline_write')) + close setlocal statusline=%!SandboxStatusLine() | redrawstatus - call assert_equal('status line', Screenline(&lines - 1)) + call assert_equal('status line', Screenline(12)) call assert_equal(['after'], readfile('Xsandboxstatusline_write')) call writefile(['before'], 'Xsandboxstatusline_write') @@ -663,19 +677,25 @@ func Test_statusline_in_sandbox() call assert_fails('redrawstatus', 'E48:') call assert_equal(['before'], readfile('Xsandboxstatusline_write')) - exe a:set_cmd1 'statusline=%!SandboxStatusLine()' | redrawstatus + 5split + call assert_fails('redrawstatus!', 'E48:') + call assert_equal(['before'], readfile('Xsandboxstatusline_write')) + + exe a:set_cmd1 'statusline=%!SandboxStatusLine()' | redrawstatus! call assert_equal('', &l:statusline) - call assert_equal('status line', Screenline(&lines - 1)) + call assert_equal('status line', Screenline(6)) + call assert_equal('status line', Screenline(12)) call assert_equal(['after'], readfile('Xsandboxstatusline_write')) - bw! + bwipe! endfunc + set noequalalways call Check_statusline_in_sandbox('setglobal', 'setglobal') call Check_statusline_in_sandbox('setglobal', 'set') call Check_statusline_in_sandbox('set', 'setglobal') call Check_statusline_in_sandbox('set', 'set') - set statusline& + set equalalways& statusline& delfunc SandboxStatusLine delfunc Check_statusline_in_sandbox endfunc diff --git a/src/textformat.c b/src/textformat.c index 1af4b2f4d1..f160d1d879 100644 --- a/src/textformat.c +++ b/src/textformat.c @@ -938,8 +938,8 @@ fex_format( long count, int c) // character to be inserted { - int use_sandbox = was_set_insecurely((char_u *)"formatexpr", - OPT_LOCAL); + int use_sandbox = was_set_insecurely(curwin, + (char_u *)"formatexpr", OPT_LOCAL); int r; char_u *fex; sctx_T save_sctx = current_sctx; diff --git a/src/version.c b/src/version.c index ba653958a5..7abd1e7a2a 100644 --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1808, /**/ 1807, /**/