patch 9.2.1187: tuple type with many items reads past the end of an array

Problem:  A tuple type with more than 127 items gets a wrong item count
          and reads past the end of an array.  Allocation failure for a
          tuple type is not handled.
Solution: Use an int for the item count.  Use the "any" type when
          allocation fails (Hirohito Higashi).

closes: #21517

Assisted-by: Claude
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Hirohito Higashi authored and Christian Brabandt committed 2026-10-14 18:37:36 +00:00
1 parent 26d8c85188
commit 21e109b324
6 files changed
+46 -8

No files matched your search

+1
View File
@@ -47,5 +47,6 @@ typedef enum {
aid_get_func,
aid_defer,
aid_tuple_append,
aid_tuple_type_args,
aid_last
} alloc_id_T;
+2 -2
View File
@@ -1640,8 +1640,8 @@ typedef enum
// A type specification.
struct type_S {
vartype_T tt_type;
int8_T tt_argcount; // for func, incl. vararg, -1 for unknown
int8_T tt_min_argcount; // number of non-optional arguments
int tt_argcount; // for func, incl. vararg, -1 for unknown
int tt_min_argcount; // number of non-optional arguments
short_u tt_flags; // TTFLAG_ values
type_T *tt_member; // for list, dict, func return type
class_T *tt_class; // for class and object
+32
View File
@@ -2542,4 +2542,36 @@ func Test_tuple_unpack_memory_fail()
unlet t
endfunc
" Memory allocation failure while creating a tuple type
func Test_tuple_type_memory_fail()
let lines =<< trim END
var t = (1, 'a')
END
call test_alloc_fail(GetAllocId('tuple_type_args'), 0, 0)
call v9.CheckSourceDefFailure(lines, 'E342:')
let lines =<< trim END
var t = (1,) + ('a',)
END
call test_alloc_fail(GetAllocId('tuple_type_args'), 2, 0)
call v9.CheckSourceDefFailure(lines, 'E342:')
endfunc
" Test for a tuple type with more than 127 items
func Test_tuple_type_many_items()
let types = repeat(['number'], 300)->join(', ')
let lines =<< trim eval END
var t: tuple<{types}> = ({range(300)->join(', ')})
assert_equal(299, t[299])
assert_equal('tuple<{types}>', typename(t))
END
call v9.CheckSourceDefAndScriptSuccess(lines)
let types = repeat(['number'], 200)->join(', ')
let lines =<< trim eval END
var t: tuple<{types}> = ({repeat(["'x'"], 200)->join(', ')})
END
call v9.CheckSourceDefAndScriptFailure(lines, 'E1012:', 1)
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+2
View File
@@ -743,6 +743,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1187,
/**/
1186,
/**/
+2 -1
View File
@@ -317,7 +317,8 @@ set_tuple_union_type_on_stack(type_T *type1, type_T *type2, cctx_T *cctx)
type_T *new_tuple_type = get_tuple_type(&tuple_types_ga,
cctx->ctx_type_list);
// result inherits the variadic flag from the operands
new_tuple_type->tt_flags |= (type1->tt_flags & TTFLAG_VARARGS)
if ((new_tuple_type->tt_flags & TTFLAG_STATIC) == 0)
new_tuple_type->tt_flags |= (type1->tt_flags & TTFLAG_VARARGS)
| (type2->tt_flags & TTFLAG_VARARGS);
// set the type on the stack for the resulting tuple
+7 -5
View File
@@ -321,7 +321,8 @@ tuple_type_add_types(
// pointer to type_gap.
if (ga_grow(type_gap, 1) == FAIL)
return FAIL;
tupletype->tt_args = ALLOC_CLEAR_MULT(type_T *, typecount);
tupletype->tt_args = alloc_clear_id(sizeof(type_T *) * typecount,
aid_tuple_type_args);
if (tupletype->tt_args == NULL)
return FAIL;
((type_T **)type_gap->ga_data)[type_gap->ga_len] =
@@ -389,7 +390,7 @@ get_tuple_type(garray_T *tuple_types_gap, garray_T *type_gap)
if (typecount > 0)
{
if (tuple_type_add_types(type, typecount, type_gap) == FAIL)
return NULL;
return &t_any;
mch_memmove(type->tt_args, tuple_types, sizeof(type_T *) * typecount);
}
type->tt_argcount = typecount;
@@ -1919,13 +1920,14 @@ parse_type_tuple(
*arg = p + 1;
ret_type = alloc_tuple_type(typecount, type_gap);
ret_type->tt_flags = flags;
ret_type->tt_argcount = typecount;
if (tuple_type_add_types(ret_type, typecount, type_gap) == FAIL)
if (ret_type == &t_any
|| tuple_type_add_types(ret_type, typecount, type_gap) == FAIL)
{
ret_type = NULL;
goto on_err;
}
ret_type->tt_flags = flags;
ret_type->tt_argcount = typecount;
mch_memmove(ret_type->tt_args, tuple_types_ga.ga_data,
sizeof(type_T *) * typecount);