aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer.c5
-rw-r--r--src/nvim/eval.c19
-rw-r--r--src/nvim/ex_cmds.lua2
-rw-r--r--src/nvim/testdir/test_functions.vim16
-rw-r--r--src/nvim/testdir/test_python2.vim84
-rw-r--r--src/nvim/testdir/test_python3.vim84
6 files changed, 208 insertions, 2 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index e333f552a8..d67783baa0 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -4943,7 +4943,12 @@ chk_modeline (
if (*s != NUL) { /* skip over an empty "::" */
save_SID = current_SID;
current_SID = SID_MODELINE;
+ // Make sure no risky things are executed as a side effect.
+ sandbox++;
+
retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
+
+ sandbox--;
current_SID = save_SID;
if (retval == FAIL) /* stop if error found */
break;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index df677a3a13..0961e5fd92 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -241,13 +241,14 @@ typedef enum {
///< the value (prevents error message).
} GetLvalFlags;
-// function flags
+// flags used in uf_flags
#define FC_ABORT 0x01 // abort function on error
#define FC_RANGE 0x02 // function accepts range
#define FC_DICT 0x04 // Dict function, uses "self"
#define FC_CLOSURE 0x08 // closure, uses outer scope variables
#define FC_DELETED 0x10 // :delfunction used while uf_refcount > 0
#define FC_REMOVED 0x20 // function redefined while uf_refcount > 0
+#define FC_SANDBOX 0x40 // function defined in the sandbox
// The names of packages that once were loaded are remembered.
static garray_T ga_loaded = { 0, 0, sizeof(char_u *), 4, NULL };
@@ -5853,6 +5854,9 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool evaluate)
if (prof_def_func()) {
func_do_profile(fp);
}
+ if (sandbox) {
+ flags |= FC_SANDBOX;
+ }
fp->uf_varargs = true;
fp->uf_flags = flags;
fp->uf_calls = 0;
@@ -20352,6 +20356,9 @@ void ex_function(exarg_T *eap)
if (prof_def_func())
func_do_profile(fp);
fp->uf_varargs = varargs;
+ if (sandbox) {
+ flags |= FC_SANDBOX;
+ }
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
@@ -21342,6 +21349,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
scid_T save_current_SID;
+ bool using_sandbox = false;
funccall_T *fc;
int save_did_emsg;
static int depth = 0;
@@ -21499,6 +21507,12 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 1;
+
+ if (fp->uf_flags & FC_SANDBOX) {
+ using_sandbox = true;
+ sandbox++;
+ }
+
// need space for new sourcing_name:
// * save_sourcing_name
// * "["number"].." or "function "
@@ -21659,6 +21673,9 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
if (do_profiling_yes) {
script_prof_restore(&wait_start);
}
+ if (using_sandbox) {
+ sandbox--;
+ }
if (p_verbose >= 12 && sourcing_name != NULL) {
++no_wait_return;
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 4806eff1b4..0f69d476f9 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -1004,7 +1004,7 @@ return {
},
{
command='function',
- flags=bit.bor(EXTRA, BANG, CMDWIN),
+ flags=bit.bor(EXTRA, BANG, SBOXOK, CMDWIN),
addr_type=ADDR_LINES,
func='ex_function',
},
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 824baffbc9..c0faf1acdc 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1049,3 +1049,19 @@ func Test_func_range_with_edit()
call delete('Xfuncrange2')
bwipe!
endfunc
+
+sandbox function Fsandbox()
+ normal ix
+endfunc
+
+func Test_func_sandbox()
+ sandbox let F = {-> 'hello'}
+ call assert_equal('hello', F())
+
+ sandbox let F = {-> execute("normal ix\<Esc>")}
+ call assert_fails('call F()', 'E48:')
+ unlet F
+
+ call assert_fails('call Fsandbox()', 'E48:')
+ delfunc Fsandbox
+endfunc
diff --git a/src/nvim/testdir/test_python2.vim b/src/nvim/testdir/test_python2.vim
index 5ba9fd68cf..448785db6d 100644
--- a/src/nvim/testdir/test_python2.vim
+++ b/src/nvim/testdir/test_python2.vim
@@ -52,3 +52,87 @@ func Test_vim_function()
py del f
delfunc s:foo
endfunc
+
+func _SetUpHiddenBuffer()
+ py import vim
+ new
+ edit hidden
+ setlocal bufhidden=hide
+
+ enew
+ let lnum = 0
+ while lnum < 10
+ call append( 1, string( lnum ) )
+ let lnum = lnum + 1
+ endwhile
+ normal G
+
+ call assert_equal( line( '.' ), 11 )
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Clear()
+ call _SetUpHiddenBuffer()
+ py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = None
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_List()
+ call _SetUpHiddenBuffer()
+ py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = [ 'test' ]
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Str()
+ call _SetUpHiddenBuffer()
+ py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = 'test'
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine()
+ call _SetUpHiddenBuffer()
+ py vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = None
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func _SetUpVisibleBuffer()
+ py import vim
+ new
+ let lnum = 0
+ while lnum < 10
+ call append( 1, string( lnum ) )
+ let lnum = lnum + 1
+ endwhile
+ normal G
+ call assert_equal( line( '.' ), 11 )
+endfunc
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_Clear()
+ call _SetUpVisibleBuffer()
+
+ py vim.current.buffer[:] = None
+ call assert_equal( line( '.' ), 1 )
+
+ bwipe!
+endfunc
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_List()
+ call _SetUpVisibleBuffer()
+
+ py vim.current.buffer[:] = [ 'test' ]
+ call assert_equal( line( '.' ), 1 )
+
+ bwipe!
+endfunction
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_Str()
+ call _SetUpVisibleBuffer()
+
+ py vim.current.buffer[-1] = None
+ call assert_equal( line( '.' ), 10 )
+
+ bwipe!
+endfunction
diff --git a/src/nvim/testdir/test_python3.vim b/src/nvim/testdir/test_python3.vim
index 2e3fc93674..d5b1cb1b34 100644
--- a/src/nvim/testdir/test_python3.vim
+++ b/src/nvim/testdir/test_python3.vim
@@ -52,3 +52,87 @@ func Test_vim_function()
py3 del f
delfunc s:foo
endfunc
+
+func _SetUpHiddenBuffer()
+ py3 import vim
+ new
+ edit hidden
+ setlocal bufhidden=hide
+
+ enew
+ let lnum = 0
+ while lnum < 10
+ call append( 1, string( lnum ) )
+ let lnum = lnum + 1
+ endwhile
+ normal G
+
+ call assert_equal( line( '.' ), 11 )
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Clear()
+ call _SetUpHiddenBuffer()
+ py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = None
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_List()
+ call _SetUpHiddenBuffer()
+ py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][:] = [ 'test' ]
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_Str()
+ call _SetUpHiddenBuffer()
+ py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = 'test'
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func Test_Write_To_HiddenBuffer_Does_Not_Fix_Cursor_ClearLine()
+ call _SetUpHiddenBuffer()
+ py3 vim.buffers[ int( vim.eval( 'bufnr("hidden")' ) ) ][0] = None
+ call assert_equal( line( '.' ), 11 )
+ bwipe!
+endfunc
+
+func _SetUpVisibleBuffer()
+ py3 import vim
+ new
+ let lnum = 0
+ while lnum < 10
+ call append( 1, string( lnum ) )
+ let lnum = lnum + 1
+ endwhile
+ normal G
+ call assert_equal( line( '.' ), 11 )
+endfunc
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_Clear()
+ call _SetUpVisibleBuffer()
+
+ py3 vim.current.buffer[:] = None
+ call assert_equal( line( '.' ), 1 )
+
+ bwipe!
+endfunc
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_List()
+ call _SetUpVisibleBuffer()
+
+ py3 vim.current.buffer[:] = [ 'test' ]
+ call assert_equal( line( '.' ), 1 )
+
+ bwipe!
+endfunction
+
+func Test_Write_To_Current_Buffer_Fixes_Cursor_Str()
+ call _SetUpVisibleBuffer()
+
+ py3 vim.current.buffer[-1] = None
+ call assert_equal( line( '.' ), 10 )
+
+ bwipe!
+endfunction