patch 9.1.1997: Missing out-of-memory check in vim9class.c
Commit:
https://github.com/vim/vim/commit/de701aee9f67d7c50e8b88c862f55a84de742b15
Author: John Marriott <
basi...@internode.on.net>
Date: Wed Dec 17 22:31:59 2025 +0100
patch 9.1.1997: Missing out-of-memory check in vim9class.c
Problem: Missing out-of-memory check in vim9class.c in calls to
vim_strnsave().
Solution: Refactor is_duplicate_variable() and is_duplicate_enum() and
make use of string_T struct instead (John Marriott).
closes: #18947
Signed-off-by: John Marriott <
basi...@internode.on.net>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/version.c b/src/version.c
index 1ae59e0fd..a8783de4b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1997,
/**/
1996,
/**/
diff --git a/src/vim9class.c b/src/vim9class.c
index d6a579cad..315ba4696 100644
--- a/src/vim9class.c
+++ b/src/vim9class.c
@@ -1024,10 +1024,20 @@ is_duplicate_variable(
char_u *varname,
char_u *varname_end)
{
- char_u *name = vim_strnsave(varname, varname_end - varname);
- char_u *pstr = (*name == '_') ? name + 1 : name;
+ string_T pstr = {varname, (size_t)(varname_end - varname)}; // Note: the .string field may
+ // point to a string longer
+ // than the .length field.
+ // So we need to use STRNCMP()
+ // to compare it.
int dup = FALSE;
+ // Step over a leading '_'.
+ if (*pstr.string == '_')
+ {
+ pstr.string++;
+ pstr.length--;
+ }
+
for (int loop = 1; loop <= 2; loop++)
{
// loop == 1: class variables, loop == 2: object variables
@@ -1037,16 +1047,20 @@ is_duplicate_variable(
ocmember_T *m = ((ocmember_T *)vgap->ga_data) + i;
char_u *qstr = *m->ocm_name == '_' ? m->ocm_name + 1
: m->ocm_name;
- if (STRCMP(pstr, qstr) == 0)
+ if (STRNCMP(pstr.string, qstr, pstr.length) == 0
+ && qstr[pstr.length] == NUL)
{
- semsg(_(e_duplicate_variable_str), name);
+ char_u save_c = *varname_end;
+
+ *varname_end = NUL;
+ semsg(_(e_duplicate_variable_str), varname);
+ *varname_end = save_c;
dup = TRUE;
break;
}
}
}
- vim_free(name);
return dup;
}
@@ -1627,21 +1641,29 @@ is_duplicate_enum(
char_u *varname,
char_u *varname_end)
{
- char_u *name = vim_strnsave(varname, varname_end - varname);
+ string_T name = {varname, (size_t)(varname_end - varname)}; // Note: the .string field may
+ // point to a string longer
+ // than the .length field.
+ // So we need to use STRNCMP()
+ // to compare it.
int dup = FALSE;
for (int i = 0; i < enum_gap->ga_len; ++i)
{
ocmember_T *m = ((ocmember_T *)enum_gap->ga_data) + i;
- if (STRCMP(name, m->ocm_name) == 0)
+ if (STRNCMP(name.string, m->ocm_name, name.length) == 0
+ && m->ocm_name[name.length] == NUL)
{
- semsg(_(e_duplicate_enum_str), name);
+ char_u save_c = *varname_end;
+
+ *varname_end = NUL;
+ semsg(_(e_duplicate_enum_str), varname);
+ *varname_end = save_c;
dup = TRUE;
break;
}
}
- vim_free(name);
return dup;
}