changeset 31435:8fe720031437 v9.0.1050

patch 9.0.1050: using freed memory when assigning to variable twice Commit: https://github.com/vim/vim/commit/6342e2c5a6570231aefabd8e34c2f2cb22f6927a Author: Bram Moolenaar <Bram@vim.org> Date: Mon Dec 12 18:56:32 2022 +0000 patch 9.0.1050: using freed memory when assigning to variable twice Problem: Using freed memory when assigning to variable twice. Solution: Make copy of the list type. (closes https://github.com/vim/vim/issues/11691)
author Bram Moolenaar <Bram@vim.org>
date Mon, 12 Dec 2022 20:00:04 +0100
parents 82f2f32bbe5e
children 8e20602d3d90
files src/testdir/test_vim9_script.vim src/version.c src/vim9type.c
diffstat 3 files changed, 34 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -4519,6 +4519,36 @@ def Test_echo_uninit_variables()
   endif
 enddef
 
+def Test_free_type_before_use()
+  # this rather complicated script was freeing a type before using it
+  var lines =<< trim END
+      vim9script
+
+      def Scan(rel: list<dict<any>>): func(func(dict<any>))
+        return (Emit: func(dict<any>)) => {
+          for t in rel
+            Emit(t)
+          endfor
+        }
+      enddef
+
+      def Build(Cont: func(func(dict<any>))): list<dict<any>>
+        var rel: list<dict<any>> = []
+        Cont((t) => {
+            add(rel, t)
+        })
+        return rel
+      enddef
+
+      var R = [{A: 0}]
+      var result = Scan(R)->Build()
+      result = Scan(R)->Build()
+
+      assert_equal(R, result)
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 " Keep this last, it messes up highlighting.
 def Test_substitute_cmd()
   new
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1050,
+/**/
     1049,
 /**/
     1048,
--- a/src/vim9type.c
+++ b/src/vim9type.c
@@ -403,7 +403,8 @@ typval2type_int(typval_T *tv, int copyID
 	if (l->lv_type != NULL && (l->lv_first == NULL
 					   || (flags & TVTT_MORE_SPECIFIC) == 0
 					   || l->lv_type->tt_member != &t_any))
-	    return l->lv_type;
+	    // make a copy, lv_type may be freed if the list is freed
+	    return copy_type(l->lv_type, type_gap);
 	if (l->lv_first == &range_list_item)
 	    return &t_list_number;
 	if (l->lv_copyID == copyID)