mirror of
https://github.com/neovim/neovim.git
synced 2025-10-10 11:56:30 +00:00
vim-patch:8.1.0798: changing a blob while iterating over it works strangely
Problem: Changing a blob while iterating over it works strangely.
Solution: Make a copy of the Blob before iterating.
dd29ea1805
This commit is contained in:
@@ -2599,15 +2599,16 @@ void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip)
|
|||||||
fi->fi_lw.lw_item = tv_list_first(l);
|
fi->fi_lw.lw_item = tv_list_first(l);
|
||||||
}
|
}
|
||||||
} else if (tv.v_type == VAR_BLOB) {
|
} else if (tv.v_type == VAR_BLOB) {
|
||||||
blob_T *const b = tv.vval.v_blob;
|
|
||||||
if (b == NULL) {
|
|
||||||
tv_clear(&tv);
|
|
||||||
} else {
|
|
||||||
// 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;
|
fi->fi_bi = 0;
|
||||||
|
if (tv.vval.v_blob != NULL) {
|
||||||
|
typval_T btv;
|
||||||
|
|
||||||
|
// Make a copy, so that the iteration still works when the
|
||||||
|
// blob is changed.
|
||||||
|
tv_blob_copy(&tv, &btv);
|
||||||
|
fi->fi_blob = btv.vval.v_blob;
|
||||||
}
|
}
|
||||||
|
tv_clear(&tv);
|
||||||
} else {
|
} else {
|
||||||
EMSG(_(e_listreq));
|
EMSG(_(e_listreq));
|
||||||
tv_clear(&tv);
|
tv_clear(&tv);
|
||||||
@@ -9737,17 +9738,7 @@ int var_item_copy(const vimconv_T *const conv,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VAR_BLOB:
|
case VAR_BLOB:
|
||||||
to->v_type = VAR_BLOB;
|
tv_blob_copy(from, to);
|
||||||
if (from->vval.v_blob == NULL) {
|
|
||||||
to->vval.v_blob = NULL;
|
|
||||||
} else {
|
|
||||||
tv_blob_alloc_ret(to);
|
|
||||||
const int len = from->vval.v_blob->bv_ga.ga_len;
|
|
||||||
|
|
||||||
to->vval.v_blob->bv_ga.ga_data
|
|
||||||
= xmemdup(from->vval.v_blob->bv_ga.ga_data, (size_t)len);
|
|
||||||
to->vval.v_blob->bv_ga.ga_len = len;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case VAR_DICT:
|
case VAR_DICT:
|
||||||
to->v_type = VAR_DICT;
|
to->v_type = VAR_DICT;
|
||||||
|
@@ -2252,6 +2252,30 @@ void tv_blob_alloc_ret(typval_T *const ret_tv)
|
|||||||
tv_blob_set_ret(ret_tv, b);
|
tv_blob_set_ret(ret_tv, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy a blob typval to a different typval.
|
||||||
|
///
|
||||||
|
/// @param[in] from Blob object to copy from.
|
||||||
|
/// @param[out] to Blob object to copy to.
|
||||||
|
void tv_blob_copy(typval_T *const from, typval_T *const to)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
assert(from->v_type == VAR_BLOB);
|
||||||
|
|
||||||
|
to->v_type = VAR_BLOB;
|
||||||
|
if (from->vval.v_blob == NULL) {
|
||||||
|
to->vval.v_blob = NULL;
|
||||||
|
} else {
|
||||||
|
tv_blob_alloc_ret(to);
|
||||||
|
const int len = from->vval.v_blob->bv_ga.ga_len;
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
to->vval.v_blob->bv_ga.ga_data
|
||||||
|
= xmemdup(from->vval.v_blob->bv_ga.ga_data, (size_t)len);
|
||||||
|
}
|
||||||
|
to->vval.v_blob->bv_ga.ga_len = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//{{{3 Clear
|
//{{{3 Clear
|
||||||
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
|
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
|
||||||
|
|
||||||
|
@@ -154,6 +154,7 @@ func Test_blob_for_loop()
|
|||||||
call assert_equal(i, byte)
|
call assert_equal(i, byte)
|
||||||
let i += 1
|
let i += 1
|
||||||
endfor
|
endfor
|
||||||
|
call assert_equal(4, i)
|
||||||
|
|
||||||
let blob = 0z00
|
let blob = 0z00
|
||||||
call remove(blob, 0)
|
call remove(blob, 0)
|
||||||
@@ -161,6 +162,19 @@ func Test_blob_for_loop()
|
|||||||
for byte in blob
|
for byte in blob
|
||||||
call assert_error('loop over empty blob')
|
call assert_error('loop over empty blob')
|
||||||
endfor
|
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
|
endfunc
|
||||||
|
|
||||||
func Test_blob_concatenate()
|
func Test_blob_concatenate()
|
||||||
|
Reference in New Issue
Block a user