summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-01-23 21:56:21 +0100
committerBram Moolenaar <Bram@vim.org>2019-01-23 21:56:21 +0100
commitdd29ea18050284526174b5685781469240f5bc4a (patch)
tree2dd4aa32dab187e6a6973303da6fcb13c4ba5d38 /src
parentbf821bccf18453b01d25bee53e4954b02a5dd0e6 (diff)
downloadvim-git-dd29ea18050284526174b5685781469240f5bc4a.tar.gz
patch 8.1.0798: changing a blob while iterating over it works strangelyv8.1.0798
Problem: Changing a blob while iterating over it works strangely. Solution: Make a copy of the Blob before iterating.
Diffstat (limited to 'src')
-rw-r--r--src/blob.c22
-rw-r--r--src/eval.c34
-rw-r--r--src/proto/blob.pro1
-rw-r--r--src/testdir/test_blob.vim14
-rw-r--r--src/version.c2
5 files changed, 50 insertions, 23 deletions
diff --git a/src/blob.c b/src/blob.c
index bba998913..a95403033 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -57,6 +57,28 @@ rettv_blob_set(typval_T *rettv, blob_T *b)
++b->bv_refcount;
}
+ int
+blob_copy(typval_T *from, typval_T *to)
+{
+ int ret = OK;
+
+ to->v_type = VAR_BLOB;
+ if (from->vval.v_blob == NULL)
+ to->vval.v_blob = NULL;
+ else if (rettv_blob_alloc(to) == FAIL)
+ ret = FAIL;
+ else
+ {
+ int len = from->vval.v_blob->bv_ga.ga_len;
+
+ if (len > 0)
+ to->vval.v_blob->bv_ga.ga_data =
+ vim_memsave(from->vval.v_blob->bv_ga.ga_data, len);
+ to->vval.v_blob->bv_ga.ga_len = len;
+ }
+ return ret;
+}
+
void
blob_free(blob_T *b)
{
diff --git a/src/eval.c b/src/eval.c
index d1a7fd37d..dac086f85 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2587,7 +2587,6 @@ eval_for_line(
char_u *expr;
typval_T tv;
list_T *l;
- blob_T *b;
*errp = TRUE; /* default: there is an error */
@@ -2632,16 +2631,17 @@ eval_for_line(
}
else if (tv.v_type == VAR_BLOB)
{
- b = tv.vval.v_blob;
- if (b == NULL)
- clear_tv(&tv);
- else
+ fi->fi_bi = 0;
+ if (tv.vval.v_blob != NULL)
{
- // No need to increment the refcount, it's already set for
- // the blob being used in "tv".
- fi->fi_blob = b;
- fi->fi_bi = 0;
+ typval_T btv;
+
+ // Make a copy, so that the iteration still works when the
+ // blob is changed.
+ blob_copy(&tv, &btv);
+ fi->fi_blob = btv.vval.v_blob;
}
+ clear_tv(&tv);
}
else
{
@@ -8076,7 +8076,7 @@ tv_check_lock(int lock, char_u *name, int use_gettext)
/*
* Copy the values from typval_T "from" to typval_T "to".
* When needed allocates string or increases reference count.
- * Does not make a copy of a list or dict but copies the reference!
+ * Does not make a copy of a list, blob or dict but copies the reference!
* It is OK for "from" and "to" to point to the same item. This is used to
* make a copy later.
*/
@@ -8216,19 +8216,7 @@ item_copy(
ret = FAIL;
break;
case VAR_BLOB:
- to->v_type = VAR_BLOB;
- if (from->vval.v_blob == NULL)
- to->vval.v_blob = NULL;
- else if (rettv_blob_alloc(to) == FAIL)
- ret = FAIL;
- else
- {
- int len = from->vval.v_blob->bv_ga.ga_len;
-
- to->vval.v_blob->bv_ga.ga_data =
- vim_memsave(from->vval.v_blob->bv_ga.ga_data, len);
- to->vval.v_blob->bv_ga.ga_len = len;
- }
+ ret = blob_copy(from, to);
break;
case VAR_DICT:
to->v_type = VAR_DICT;
diff --git a/src/proto/blob.pro b/src/proto/blob.pro
index 1c6452486..b8e48deee 100644
--- a/src/proto/blob.pro
+++ b/src/proto/blob.pro
@@ -2,6 +2,7 @@
blob_T *blob_alloc(void);
int rettv_blob_alloc(typval_T *rettv);
void rettv_blob_set(typval_T *rettv, blob_T *b);
+int blob_copy(typval_T *from, typval_T *to);
void blob_free(blob_T *b);
void blob_unref(blob_T *b);
long blob_len(blob_T *b);
diff --git a/src/testdir/test_blob.vim b/src/testdir/test_blob.vim
index 964ed2279..9eb205774 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -154,6 +154,7 @@ func Test_blob_for_loop()
call assert_equal(i, byte)
let i += 1
endfor
+ call assert_equal(4, i)
let blob = 0z00
call remove(blob, 0)
@@ -161,6 +162,19 @@ func Test_blob_for_loop()
for byte in blob
call assert_error('loop over empty blob')
endfor
+
+ let blob = 0z0001020304
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ if i == 1
+ call remove(blob, 0)
+ elseif i == 3
+ call remove(blob, 3)
+ endif
+ let i += 1
+ endfor
+ call assert_equal(5, i)
endfunc
func Test_blob_concatenate()
diff --git a/src/version.c b/src/version.c
index e22ebcb37..a260844d2 100644
--- a/src/version.c
+++ b/src/version.c
@@ -792,6 +792,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 798,
+/**/
797,
/**/
796,