]> granicus.if.org Git - vim/commitdiff
patch 8.2.1867: Vim9: argument to add() not checked for blob v8.2.1867
authorBram Moolenaar <Bram@vim.org>
Mon, 19 Oct 2020 18:45:36 +0000 (20:45 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 19 Oct 2020 18:45:36 +0000 (20:45 +0200)
Problem:    Vim9: argument to add() not checked for blob.
Solution:   Add the BLOBAPPEND instruction.

src/errors.h
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_func.vim
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index 8ddf4415732466be3082c73f45597f4d8248ef3c..4d8456ffe0deea632d5f0fe8d96e70f10b40c578 100644 (file)
@@ -284,4 +284,6 @@ EXTERN char e_throw_with_empty_string[]
        INIT(= N_("E1129: Throw with empty string"));
 EXTERN char e_cannot_add_to_null_list[]
        INIT(= N_("E1130: Cannot add to null list"));
+EXTERN char e_cannot_add_to_null_blob[]
+       INIT(= N_("E1131: Cannot add to null blob"));
 #endif
index fe1ce66ec5b3c71c82fb875d951333e704a1f1fa..97797bc03add993daec3dd91151b45300c7f99e7 100644 (file)
@@ -301,6 +301,34 @@ def Test_disassemble_list_add()
         res)
 enddef
 
+def s:BlobAdd()
+  var b: blob = 0z
+  add(b, 123)
+  add(b, g:aNumber)
+enddef
+
+def Test_disassemble_blob_add()
+  var res = execute('disass s:BlobAdd')
+  assert_match('<SNR>\d*_BlobAdd\_s*' ..
+        'var b: blob = 0z\_s*' ..
+        '\d PUSHBLOB 0z\_s*' ..
+        '\d STORE $0\_s*' ..
+        'add(b, 123)\_s*' ..
+        '\d LOAD $0\_s*' ..
+        '\d PUSHNR 123\_s*' ..
+        '\d BLOBAPPEND\_s*' ..
+        '\d DROP\_s*' ..
+        'add(b, g:aNumber)\_s*' ..
+        '\d LOAD $0\_s*' ..
+        '\d\+ LOADG g:aNumber\_s*' ..
+        '\d\+ CHECKTYPE number stack\[-1\]\_s*' ..
+        '\d\+ BLOBAPPEND\_s*' ..
+        '\d\+ DROP\_s*' ..
+        '\d\+ PUSHNR 0\_s*' ..
+        '\d\+ RETURN',
+        res)
+enddef
+
 def s:ScriptFuncUnlet()
   g:somevar = "value"
   unlet g:somevar
index 4af136cefec35541b63776623e2e9389910eb3c3..e8072d375560e3910078c3cd1e8f180a31bd8abe 100644 (file)
@@ -1791,9 +1791,25 @@ def Test_list_add()
 enddef
 
 def Test_blob_add()
-  var b: blob = 0z12
-  add(b, 0x34)
-  assert_equal(0z1234, b)
+  var b1: blob = 0z12
+  add(b1, 0x34)
+  assert_equal(0z1234, b1)
+
+  var b2: blob # defaults to empty blob
+  add(b2, 0x67)
+  assert_equal(0z67, b2)
+
+  var lines =<< trim END
+      var b: blob
+      add(b, "x")
+  END
+  CheckDefFailure(lines, 'E1012:', 2)
+
+  lines =<< trim END
+      var b: blob = test_null_blob()
+      add(b, 123)
+  END
+  CheckDefExecFailure(lines, 'E1131:', 2)
 enddef
 
 def SID(): number
index 1b60ebd2a0c97ae1a7a3d33d4c798631363901e9..97a3b71dbadca3a93c4a44dae54526ee550cb30c 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1867,
 /**/
     1866,
 /**/
index 4cece6d81476f4da6e83c76f82c68e29fc52061d..68b9bfab3897168a0b18dfbe7cc24dcbfd1dcc83 100644 (file)
@@ -126,6 +126,7 @@ typedef enum {
     ISN_ANYINDEX,   // [expr] runtime index
     ISN_ANYSLICE,   // [expr:expr] runtime slice
     ISN_SLICE,     // drop isn_arg.number items from start of list
+    ISN_BLOBAPPEND, // append to a blob, like add()
     ISN_GETITEM,    // push list item, isn_arg.number is the index
     ISN_MEMBER,            // dict[member]
     ISN_STRINGMEMBER, // dict.member using isn_arg.string
index bb4807eeb7e63a8a5f7ae2458a99e674e982126b..d9908d30bec0c3b58acae4621e9bf0fb5f88d377 100644 (file)
@@ -1520,6 +1520,28 @@ generate_LISTAPPEND(cctx_T *cctx)
     return OK;
 }
 
+/*
+ * Generate an ISN_BLOBAPPEND instruction.  Works like add().
+ * Argument count is already checked.
+ */
+    static int
+generate_BLOBAPPEND(cctx_T *cctx)
+{
+    garray_T   *stack = &cctx->ctx_type_stack;
+    type_T     *item_type;
+
+    // Caller already checked that blob_type is a blob.
+    item_type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
+    if (need_type(item_type, &t_number, -1, cctx, FALSE, FALSE) == FAIL)
+       return FAIL;
+
+    if (generate_instr(cctx, ISN_BLOBAPPEND) == NULL)
+       return FAIL;
+
+    --stack->ga_len;       // drop the argument
+    return OK;
+}
+
 /*
  * Generate an ISN_DCALL or ISN_UCALL instruction.
  * Return FAIL if the number of arguments is wrong.
@@ -2570,13 +2592,18 @@ compile_call(
                type_T      *type = ((type_T **)stack->ga_data)[
                                                            stack->ga_len - 2];
 
-               // TODO: also check for VAR_BLOB
                if (type->tt_type == VAR_LIST)
                {
                    // inline "add(list, item)" so that the type can be checked
                    res = generate_LISTAPPEND(cctx);
                    idx = -1;
                }
+               else if (type->tt_type == VAR_BLOB)
+               {
+                   // inline "add(blob, nr)" so that the type can be checked
+                   res = generate_BLOBAPPEND(cctx);
+                   idx = -1;
+               }
            }
 
            if (idx >= 0)
@@ -5421,7 +5448,7 @@ compile_assignment(char_u *arg, exarg_T *eap, cmdidx_T cmdidx, cctx_T *cctx)
                        generate_PUSHS(cctx, NULL);
                        break;
                    case VAR_BLOB:
-                       generate_PUSHBLOB(cctx, NULL);
+                       generate_PUSHBLOB(cctx, blob_alloc());
                        break;
                    case VAR_FUNC:
                        generate_PUSHFUNC(cctx, NULL, &t_func_void);
@@ -7675,6 +7702,7 @@ delete_instr(isn_T *isn)
        case ISN_ANYINDEX:
        case ISN_ANYSLICE:
        case ISN_BCALL:
+       case ISN_BLOBAPPEND:
        case ISN_CATCH:
        case ISN_CHECKLEN:
        case ISN_CHECKNR:
index 031761d422de3e792de1a86f5edbae17ccdd3624..7a5871a7fb9062095ee69f639e28c67030351b2c 100644 (file)
@@ -2312,6 +2312,29 @@ call_def_function(
                }
                break;
 
+           case ISN_BLOBAPPEND:
+               {
+                   typval_T    *tv1 = STACK_TV_BOT(-2);
+                   typval_T    *tv2 = STACK_TV_BOT(-1);
+                   blob_T      *b = tv1->vval.v_blob;
+                   int         error = FALSE;
+                   varnumber_T n;
+
+                   // add a number to a blob
+                   if (b == NULL)
+                   {
+                       SOURCING_LNUM = iptr->isn_lnum;
+                       emsg(_(e_cannot_add_to_null_blob));
+                       goto on_error;
+                   }
+                   n = tv_get_number_chk(tv2, &error);
+                   if (error)
+                       goto on_error;
+                   ga_append(&b->bv_ga, (int)n);
+                   --ectx.ec_stack.ga_len;
+               }
+               break;
+
            // Computation with two arguments of unknown type
            case ISN_OPANY:
                {
@@ -3432,6 +3455,7 @@ ex_disassemble(exarg_T *eap)
            case ISN_STRINDEX: smsg("%4d STRINDEX", current); break;
            case ISN_STRSLICE: smsg("%4d STRSLICE", current); break;
            case ISN_LISTAPPEND: smsg("%4d LISTAPPEND", current); break;
+           case ISN_BLOBAPPEND: smsg("%4d BLOBAPPEND", current); break;
            case ISN_LISTINDEX: smsg("%4d LISTINDEX", current); break;
            case ISN_LISTSLICE: smsg("%4d LISTSLICE", current); break;
            case ISN_ANYINDEX: smsg("%4d ANYINDEX", current); break;