Commit: patch 9.1.1807: :set doesn't clear local insecure flag like :setlocal does

3 views
Skip to first unread message

Christian Brabandt

unread,
Sep 29, 2025, 3:45:16 PMSep 29
to vim...@googlegroups.com
patch 9.1.1807: :set doesn't clear local insecure flag like :setlocal does

Commit: https://github.com/vim/vim/commit/fec5586a45dac86f0124f1b6dbd9f61eb418313a
Author: zeertzjq <zeer...@outlook.com>
Date: Mon Sep 29 19:26:36 2025 +0000

patch 9.1.1807: :set doesn't clear local insecure flag like :setlocal does

Problem: :set doesn't clear local insecure flag like :setlocal does.
Solution: Also clear the local insecure flag when using :set (zeertzjq).

This applies to local options like 'wrap', 'foldtext' and 'foldexpr',
whose global flags are actually never used. For global-local options
like 'statusline' the behavior is already correct, so add some tests.

related: #18434

Signed-off-by: zeertzjq <zeer...@outlook.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/src/option.c b/src/option.c
index 4a4d21b88..8a495e087 100644
--- a/src/option.c
+++ b/src/option.c
@@ -831,6 +831,11 @@ set_option_default(
// The default value is not insecure.
flagsp = insecure_flag(opt_idx, opt_flags);
*flagsp = *flagsp & ~P_INSECURE;
+ if (both)
+ {
+ flagsp = insecure_flag(opt_idx, OPT_LOCAL);
+ *flagsp = *flagsp & ~P_INSECURE;
+ }
}

#ifdef FEAT_EVAL
@@ -2781,22 +2786,34 @@ did_set_option(
int value_checked) // value was checked to be safe, no need to set the
// P_INSECURE flag.
{
- long_u *p;
+ long_u *flagsp;
+ long_u *flagsp_local = NULL;
+ int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;

options[opt_idx].flags |= P_WAS_SET;

// 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.
- p = insecure_flag(opt_idx, opt_flags);
+ flagsp = insecure_flag(opt_idx, opt_flags);
+ if (both)
+ flagsp_local = insecure_flag(opt_idx, OPT_LOCAL);
if (!value_checked && (secure
#ifdef HAVE_SANDBOX
|| sandbox != 0
#endif
|| (opt_flags & OPT_MODELINE)))
- *p = *p | P_INSECURE;
+ {
+ *flagsp = *flagsp | P_INSECURE;
+ if (flagsp_local != NULL)
+ *flagsp_local = *flagsp_local | P_INSECURE;
+ }
else if (new_value)
- *p = *p & ~P_INSECURE;
+ {
+ *flagsp = *flagsp & ~P_INSECURE;
+ if (flagsp_local != NULL)
+ *flagsp_local = *flagsp_local & ~P_INSECURE;
+ }
}

/*
diff --git a/src/testdir/test_fold.vim b/src/testdir/test_fold.vim
index fc63b1572..3a00d9c2c 100644
--- a/src/testdir/test_fold.vim
+++ b/src/testdir/test_fold.vim
@@ -1669,7 +1669,7 @@ endfunc
" in a sandbox
func Test_foldtext_in_modeline()
func ModelineFoldText()
- call feedkeys('aFoo', 'xt')
+ call writefile(['after'], 'Xmodelinefoldtext_write')
return "folded text"
endfunc
let lines =<< trim END
@@ -1680,24 +1680,51 @@ func Test_foldtext_in_modeline()
END
call writefile(lines, 'Xmodelinefoldtext', 'D')

- set modeline modelineexpr
- split Xmodelinefoldtext
+ func Check_foldtext_in_modeline(set_cmd)
+ call writefile(['before'], 'Xmodelinefoldtext_write', 'D')
+ split Xmodelinefoldtext
+ call cursor(1, 1)
+ normal! zf3j
+ 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'))
+
+ setglobal foldtext&
+ call assert_equal('folded text', foldtextresult(1))
+ call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
+
+ exe a:set_cmd 'foldtext=ModelineFoldText()'
+ call assert_equal('folded text', foldtextresult(1))
+ call assert_equal(['after'], readfile('Xmodelinefoldtext_write'))
+
+ call writefile(['before'], 'Xmodelinefoldtext_write')
+ exe 'sandbox' a:set_cmd 'foldtext=ModelineFoldText()'
+ call assert_equal('folded text', foldtextresult(1))
+ call assert_equal(['before'], readfile('Xmodelinefoldtext_write'))
+
+ exe a:set_cmd 'foldtext=ModelineFoldText()'
+ call assert_equal('folded text', foldtextresult(1))
+ call assert_equal(['after'], readfile('Xmodelinefoldtext_write'))
+ bw!
+ endfunc

- call cursor(1, 1)
- normal! zf3j
- call assert_equal('folded text', foldtextresult(1))
- call assert_equal(lines, getbufline('', 1, '$'))
+ set modeline modelineexpr
+ call Check_foldtext_in_modeline('setlocal')
+ call Check_foldtext_in_modeline('set')

- bw!
set modeline& modelineexpr&
delfunc ModelineFoldText
+ delfunc Check_foldtext_in_modeline
endfunc

" Test for setting 'foldexpr' from the modeline and executing the expression
" in a sandbox
func Test_foldexpr_in_modeline()
func ModelineFoldExpr()
- call feedkeys('aFoo', 'xt')
+ call writefile(['after'], 'Xmodelinefoldexpr_write')
return strlen(matchstr(getline(v:lnum),'^\s*'))
endfunc
let lines =<< trim END
@@ -1711,15 +1738,42 @@ func Test_foldexpr_in_modeline()
END
call writefile(lines, 'Xmodelinefoldexpr', 'D')

- set modeline modelineexpr
- split Xmodelinefoldexpr
+ func Check_foldexpr_in_modeline(set_cmd)
+ call writefile(['before'], 'Xmodelinefoldexpr_write', 'D')
+ split Xmodelinefoldexpr
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))

- call assert_equal(2, foldlevel(3))
- call assert_equal(lines, getbufline('', 1, '$'))
+ setglobal foldexpr=ModelineFoldExpr()
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
+
+ setglobal foldexpr&
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
+
+ exe a:set_cmd 'foldexpr=ModelineFoldExpr()'
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['after'], readfile('Xmodelinefoldexpr_write'))
+
+ call writefile(['before'], 'Xmodelinefoldexpr_write')
+ exe 'sandbox' a:set_cmd 'foldexpr=ModelineFoldExpr()'
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['before'], readfile('Xmodelinefoldexpr_write'))
+
+ exe a:set_cmd 'foldexpr=ModelineFoldExpr()'
+ call assert_equal(2, foldlevel(3))
+ call assert_equal(['after'], readfile('Xmodelinefoldexpr_write'))
+ bw!
+ endfunc
+
+ set modeline modelineexpr
+ call Check_foldexpr_in_modeline('setlocal')
+ call Check_foldexpr_in_modeline('set')

- bw!
set modeline& modelineexpr&
delfunc ModelineFoldExpr
+ delfunc Check_foldexpr_in_modeline
endfunc

" Make sure a fold containing a nested fold is split correctly when using
diff --git a/src/testdir/test_modeline.vim b/src/testdir/test_modeline.vim
index a5762f7f6..cb144c580 100644
--- a/src/testdir/test_modeline.vim
+++ b/src/testdir/test_modeline.vim
@@ -371,8 +371,22 @@ func Test_modeline_nowrap_lcs_extends()
\ ], 'Xmodeline_nowrap', 'D')
call NewWindow(10, 20)

+ func Check_modeline_nowrap(expect_insecure, expect_secure, set_cmd)
+ edit Xmodeline_nowrap
+ 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
+
setlocal nolist listchars=
- edit Xmodeline_nowrap
let expect_insecure = [
\ 'aaa ',
\ 'bbb ',
@@ -380,9 +394,6 @@ func Test_modeline_nowrap_lcs_extends()
\ 'ddd >',
\ '~ ',
\ ]
- call assert_equal(expect_insecure, ScreenLines([1, 5], 20))
-
- setlocal nowrap
let expect_secure = [
\ 'aaa ',
\ 'bbb ',
@@ -390,7 +401,8 @@ func Test_modeline_nowrap_lcs_extends()
\ 'ddd ',
\ '~ ',
\ ]
- call assert_equal(expect_secure, ScreenLines([1, 5], 20))
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')

setlocal list listchars=extends:+
let expect_secure = [
@@ -401,13 +413,45 @@ func Test_modeline_nowrap_lcs_extends()
\ '~ ',
\ ]
call assert_equal(expect_secure, ScreenLines([1, 5], 20))
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')

- edit Xmodeline_nowrap
- call assert_equal(expect_insecure, ScreenLines([1, 5], 20))
- setlocal nowrap
- call assert_equal(expect_secure, ScreenLines([1, 5], 20))
+ " Other 'listchars' flags are not affected.
+ call writefile([
+ \ "aa a",
+ \ "bb b",
+ \ "cc c evil",
+ \ "dd d vim: nowrap lcs=tab\:<->",
+ \ ], 'Xmodeline_nowrap')
+ let expect_insecure = [
+ \ 'aa<---->a ',
+ \ 'bb<---->b ',
+ \ 'cc<---->c >',
+ \ 'dd<---->d >',
+ \ '~ ',
+ \ ]
+ let expect_secure = [
+ \ 'aa<---->a ',
+ \ 'bb<---->b ',
+ \ 'cc<---->c ',
+ \ 'dd<---->d ',
+ \ '~ ',
+ \ ]
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')
+
+ " Same behavior even if modeline sets "extends" to a space.
+ call writefile([
+ \ "aa a",
+ \ "bb b",
+ \ "cc c evil",
+ \ "dd d vim: nowrap lcs=tab\:<->",
+ \ ], 'Xmodeline_nowrap')
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'setlocal')
+ call Check_modeline_nowrap(expect_insecure, expect_secure, 'set')

call CloseWindow()
+ delfunc Check_modeline_nowrap
endfunc

" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim
index 401eb2a04..e1f635940 100644
--- a/src/testdir/test_statusline.vim
+++ b/src/testdir/test_statusline.vim
@@ -637,4 +637,47 @@ func Test_statusline_highlight_group_cleared()
call StopVimInTerminal(buf)
endfunc

+" Test for setting both global and local 'statusline' values in a sandbox
+func Test_statusline_in_sandbox()
+ func SandboxStatusLine()
+ call writefile(['after'], 'Xsandboxstatusline_write')
+ return "status line"
+ endfunc
+
+ func Check_statusline_in_sandbox(set_cmd0, set_cmd1)
+ new | only
+ call writefile(['before'], 'Xsandboxstatusline_write', 'D')
+ setlocal statusline=
+ 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'))
+
+ setlocal statusline=%!SandboxStatusLine() | redrawstatus
+ call assert_equal('status line', Screenline(&lines - 1))
+ call assert_equal(['after'], readfile('Xsandboxstatusline_write'))
+
+ call writefile(['before'], 'Xsandboxstatusline_write')
+ setlocal statusline=
+ 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(['after'], readfile('Xsandboxstatusline_write'))
+ bw!
+ endfunc
+
+ 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&
+ delfunc SandboxStatusLine
+ delfunc Check_statusline_in_sandbox
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 900a682f8..ba653958a 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 */
+/**/
+ 1807,
/**/
1806,
/**/
Reply all
Reply to author
Forward
0 new messages