# HG changeset patch # User Bram Moolenaar # Date 1628098204 -7200 # Node ID 7144d2ffc86be688dac74e9aa3fa3f5bdc3dd08e # Parent bdb60211e4d316b8ea854e33b57caa8c2fcaae4c patch 8.2.3284: no error for insert() or remove() changing a locked blob Commit: https://github.com/vim/vim/commit/80d7395dcfe96158428da6bb3d28a6eee1244e28 Author: Sean Dewar Date: Wed Aug 4 19:25:54 2021 +0200 patch 8.2.3284: no error for insert() or remove() changing a locked blob Problem: No error for insert() or remove() changing a locked blob. Solution: Check a blob is not locked before changing it. (Sean Dewar, closes #8696) diff --git a/src/blob.c b/src/blob.c --- a/src/blob.c +++ b/src/blob.c @@ -412,16 +412,19 @@ blob_set_range(blob_T *dest, long n1, lo * "remove({blob})" function */ void -blob_remove(typval_T *argvars, typval_T *rettv) +blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg) { + blob_T *b = argvars[0].vval.v_blob; int error = FALSE; long idx; long end; + if (b != NULL && value_check_lock(b->bv_lock, arg_errmsg, TRUE)) + return; + idx = (long)tv_get_number_chk(&argvars[1], &error); if (!error) { - blob_T *b = argvars[0].vval.v_blob; int len = blob_len(b); char_u *p; diff --git a/src/errors.h b/src/errors.h --- a/src/errors.h +++ b/src/errors.h @@ -366,7 +366,8 @@ EXTERN char e_returning_value_in_functio INIT(= N_("E1096: Returning a value in a function without a return type")); EXTERN char e_line_incomplete[] INIT(= N_("E1097: Line incomplete")); -// E1098 unused +EXTERN char e_string_list_or_blob_required[] + INIT(= N_("E1098: String, List or Blob required")); EXTERN char e_unknown_error_while_executing_str[] INIT(= N_("E1099: Unknown error while executing %s")); EXTERN char e_cannot_declare_script_variable_in_function[] diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1749,7 +1749,7 @@ eval_for_line( } else { - emsg(_(e_listreq)); + emsg(_(e_string_list_or_blob_required)); clear_tv(&tv); } } diff --git a/src/list.c b/src/list.c --- a/src/list.c +++ b/src/list.c @@ -2817,45 +2817,49 @@ f_insert(typval_T *argvars, typval_T *re if (argvars[0].v_type == VAR_BLOB) { - int val, len; - char_u *p; + blob_T *b = argvars[0].vval.v_blob; - if (argvars[0].vval.v_blob == NULL) + if (b == NULL) { if (in_vim9script()) emsg(_(e_cannot_add_to_null_blob)); - return; } - - len = blob_len(argvars[0].vval.v_blob); - if (argvars[2].v_type != VAR_UNKNOWN) + else if (!value_check_lock(b->bv_lock, + (char_u *)N_("insert() argument"), TRUE)) { - before = (long)tv_get_number_chk(&argvars[2], &error); + int val, len; + char_u *p; + + len = blob_len(b); + if (argvars[2].v_type != VAR_UNKNOWN) + { + before = (long)tv_get_number_chk(&argvars[2], &error); + if (error) + return; // type error; errmsg already given + if (before < 0 || before > len) + { + semsg(_(e_invarg2), tv_get_string(&argvars[2])); + return; + } + } + val = tv_get_number_chk(&argvars[1], &error); if (error) - return; // type error; errmsg already given - if (before < 0 || before > len) + return; + if (val < 0 || val > 255) { - semsg(_(e_invarg2), tv_get_string(&argvars[2])); + semsg(_(e_invarg2), tv_get_string(&argvars[1])); return; } - } - val = tv_get_number_chk(&argvars[1], &error); - if (error) - return; - if (val < 0 || val > 255) - { - semsg(_(e_invarg2), tv_get_string(&argvars[1])); - return; + + if (ga_grow(&b->bv_ga, 1) == FAIL) + return; + p = (char_u *)b->bv_ga.ga_data; + mch_memmove(p + before + 1, p + before, (size_t)len - before); + *(p + before) = val; + ++b->bv_ga.ga_len; + + copy_tv(&argvars[0], rettv); } - - if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL) - return; - p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data; - mch_memmove(p + before + 1, p + before, (size_t)len - before); - *(p + before) = val; - ++argvars[0].vval.v_blob->bv_ga.ga_len; - - copy_tv(&argvars[0], rettv); } else if (argvars[0].v_type != VAR_LIST) semsg(_(e_listblobarg), "insert()"); @@ -2917,7 +2921,7 @@ f_remove(typval_T *argvars, typval_T *re if (argvars[0].v_type == VAR_DICT) dict_remove(argvars, rettv, arg_errmsg); else if (argvars[0].v_type == VAR_BLOB) - blob_remove(argvars, rettv); + blob_remove(argvars, rettv, arg_errmsg); else if (argvars[0].v_type == VAR_LIST) list_remove(argvars, rettv, arg_errmsg); else diff --git a/src/proto/blob.pro b/src/proto/blob.pro --- a/src/proto/blob.pro +++ b/src/proto/blob.pro @@ -18,5 +18,5 @@ int blob_slice_or_index(blob_T *blob, in int check_blob_index(long bloblen, varnumber_T n1, int quiet); int check_blob_range(long bloblen, varnumber_T n1, varnumber_T n2, int quiet); int blob_set_range(blob_T *dest, long n1, long n2, typval_T *src); -void blob_remove(typval_T *argvars, typval_T *rettv); +void blob_remove(typval_T *argvars, typval_T *rettv, char_u *arg_errmsg); /* vim: set ft=c : */ diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim --- a/src/testdir/test_blob.vim +++ b/src/testdir/test_blob.vim @@ -428,6 +428,23 @@ func Test_blob_func_remove() call remove(test_null_blob(), 1, 2) END call CheckLegacyAndVim9Failure(lines, 'E979:') + + let lines =<< trim END + let b = 0zDEADBEEF + lockvar b + call remove(b, 0) + unlockvar b + END + call CheckScriptFailure(lines, 'E741:') + + " can only check at script level, not in a :def function + let lines =<< trim END + vim9script + var b = 0zDEADBEEF + lockvar b + remove(b, 0) + END + call CheckScriptFailure(lines, 'E741:') endfunc func Test_blob_read_write() @@ -543,6 +560,22 @@ func Test_blob_insert() insert(test_null_blob(), 0x33) END call CheckDefExecAndScriptFailure(lines, 'E1131:') + + let lines =<< trim END + let b = 0zDEADBEEF + lockvar b + call insert(b, 3) + unlockvar b + END + call CheckScriptFailure(lines, 'E741:') + + let lines =<< trim END + vim9script + var b = 0zDEADBEEF + lockvar b + insert(b, 3) + END + call CheckScriptFailure(lines, 'E741:') endfunc func Test_blob_reverse() diff --git a/src/testdir/test_eval_stuff.vim b/src/testdir/test_eval_stuff.vim --- a/src/testdir/test_eval_stuff.vim +++ b/src/testdir/test_eval_stuff.vim @@ -65,9 +65,9 @@ func Test_E963() endfunc func Test_for_invalid() - call assert_fails("for x in 99", 'E714:') - call assert_fails("for x in function('winnr')", 'E714:') - call assert_fails("for x in {'a': 9}", 'E714:') + call assert_fails("for x in 99", 'E1098:') + call assert_fails("for x in function('winnr')", 'E1098:') + call assert_fails("for x in {'a': 9}", 'E1098:') if 0 /1/5/2/s/\n diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -756,6 +756,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 3284, +/**/ 3283, /**/ 3282,