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.
diff --git a/src/blob.c b/src/blob.c
index bba9989..a954030 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -57,6 +57,28 @@
 	++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 d1a7fd3..dac086f 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2587,7 +2587,6 @@
     char_u	*expr;
     typval_T	tv;
     list_T	*l;
-    blob_T	*b;
 
     *errp = TRUE;	/* default: there is an error */
 
@@ -2632,16 +2631,17 @@
 	    }
 	    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 @@
 /*
  * 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 @@
 		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 1c64524..b8e48de 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 964ed22..9eb2057 100644
--- a/src/testdir/test_blob.vim
+++ b/src/testdir/test_blob.vim
@@ -154,6 +154,7 @@
     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 @@
   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 e22ebcb..a260844 100644
--- a/src/version.c
+++ b/src/version.c
@@ -792,6 +792,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    798,
+/**/
     797,
 /**/
     796,