]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.0.2123: Problem with initializing the length of range() lists v9.0.2123
authorChristian Brabandt <cb@256bit.org>
Thu, 23 Nov 2023 19:14:28 +0000 (20:14 +0100)
committerChristian Brabandt <cb@256bit.org>
Thu, 23 Nov 2023 19:14:28 +0000 (20:14 +0100)
Problem:  Problem with initializing the length of range() lists
Solution: Set length explicitly when it shouldn't contain any items

range() may cause a wrong calculation of list length, which may later
then cause a segfault in list_find().  This is usually not a problem,
because range_list_materialize() calculates the length, when it
materializes the list.

In addition, in list_find() when the length of the range was wrongly
initialized, it may seem to be valid, so the check for list index
out-of-bounds will not be true, because it is called before the list is
actually materialized. And so we may eventually try to access a null
pointer, causing a segfault.

So this patch does 3 things:

- In f_range(), when we know that the list should be empty, explicitly
  set the list->lv_len value to zero. This should happen, when
  start is larger than end (in case the stride is positive) or
  end is larger than start when the stride is negative.
  This should fix the underlying issue properly. However,

- as a safety measure, let's check that the requested index is not
  out of range one more time, after the list has been materialized
  and return NULL in case it suddenly is.

- add a few more tests to verify the behaviour.

fixes: #13557
closes: #13563

Co-authored-by: Tim Pope <tpope@github.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
src/evalfunc.c
src/list.c
src/testdir/test_functions.vim
src/version.c

index 7f7914eca7d917f2eb01488fcb04af46a43df207..fa27d0d274a64c44a3a35f285f89a3deb5c758fc 100644 (file)
@@ -8646,7 +8646,10 @@ f_range(typval_T *argvars, typval_T *rettv)
     list->lv_u.nonmat.lv_start = start;
     list->lv_u.nonmat.lv_end = end;
     list->lv_u.nonmat.lv_stride = stride;
-    list->lv_len = (end - start) / stride + 1;
+    if (stride > 0 ? end < start : end > start)
+       list->lv_len = 0;
+    else
+       list->lv_len = (end - start) / stride + 1;
 }
 
 /*
index d1494c67d56e92119030bea4879fbfaf2f9811e5..ce1ccaa1c045cf073b17f6a440e14b51b22073e5 100644 (file)
@@ -415,6 +415,10 @@ list_find(list_T *l, long n)
 
     CHECK_LIST_MATERIALIZE(l);
 
+    // range_list_materialize may reset l->lv_len
+    if (n >= l->lv_len)
+       return NULL;
+
     // When there is a cached index may start search from there.
     if (l->lv_u.mat.lv_idx_item != NULL)
     {
index 49b688c25f3472df38807beba4facbbf061560c1..0801d2b695b768c01b5807275635f9583ec11494 100644 (file)
@@ -3052,6 +3052,9 @@ func Test_range()
   " get()
   call assert_equal(4, get(range(1, 10), 3))
   call assert_equal(-1, get(range(1, 10), 42, -1))
+  call assert_equal(0, get(range(1, 0, 2), 0))
+  call assert_equal(0, get(range(0, -1, 2), 0))
+  call assert_equal(0, get(range(-2, -1, -2), 0))
 
   " index()
   call assert_equal(1, index(range(1, 5), 2))
index 9b7fbe7229e61771062097b02480408bd589043e..1bbaac348cf30b1acb1503c2c73bedf9c3cd5a6e 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2123,
 /**/
     2122,
 /**/