1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
From: Bram Moolenaar <Bram@vim.org>
Date: Sat, 29 Apr 2023 21:38:04 +0100
Subject: patch 9.0.1499: using uninitialized memory with fuzzy matching
Problem: Using uninitialized memory with fuzzy matching.
Solution: Initialize the arrays used to store match positions.
Closes: #1035323
---
src/quickfix.c | 5 ++++-
src/search.c | 17 +++++++----------
src/testdir/test_matchfuzzy.vim | 27 +++++++++++++++++++++++++++
src/version.c | 2 ++
4 files changed, 40 insertions(+), 11 deletions(-)
diff --git a/src/quickfix.c b/src/quickfix.c
index 63dd541..799c243 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -6058,6 +6058,8 @@ vgr_match_buflines(
long lnum;
colnr_T col;
int pat_len = (int)STRLEN(spat);
+ if (pat_len > MAX_FUZZY_MATCHES)
+ pat_len = MAX_FUZZY_MATCHES;
for (lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; ++lnum)
{
@@ -6066,7 +6068,7 @@ vgr_match_buflines(
{
// Regular expression match
while (vim_regexec_multi(regmatch, curwin, buf, lnum,
- col, NULL) > 0)
+ col, NULL) > 0)
{
// Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the
@@ -6112,6 +6114,7 @@ vgr_match_buflines(
int_u sz = ARRAY_LENGTH(matches);
// Fuzzy string match
+ CLEAR_FIELD(matches);
while (fuzzy_match(str + col, spat, FALSE, &score, matches, sz) > 0)
{
// Pass the buffer number so that it gets used even for a
diff --git a/src/search.c b/src/search.c
index 1e4464b..619032c 100644
--- a/src/search.c
+++ b/src/search.c
@@ -4422,14 +4422,14 @@ fuzzy_match_recursive(
// Found match
if (vim_tolower(c1) == vim_tolower(c2))
{
- int_u recursiveMatches[MAX_FUZZY_MATCHES];
- int recursiveScore = 0;
- char_u *next_char;
-
// Supplied matches buffer was too short
if (nextMatch >= maxMatches)
return 0;
+ int recursiveScore = 0;
+ int_u recursiveMatches[MAX_FUZZY_MATCHES];
+ CLEAR_FIELD(recursiveMatches);
+
// "Copy-on-Write" srcMatches into matches
if (first_match && srcMatches)
{
@@ -4438,10 +4438,7 @@ fuzzy_match_recursive(
}
// Recursive call that "skips" this match
- if (has_mbyte)
- next_char = str + (*mb_ptr2len)(str);
- else
- next_char = str + 1;
+ char_u *next_char = str + (has_mbyte ? (*mb_ptr2len)(str) : 1);
if (fuzzy_match_recursive(fuzpat, next_char, strIdx + 1,
&recursiveScore, strBegin, strLen, matches,
recursiveMatches,
@@ -4506,8 +4503,8 @@ fuzzy_match_recursive(
* Uses char_u for match indices. Therefore patterns are limited to
* MAX_FUZZY_MATCHES characters.
*
- * Returns TRUE if 'pat_arg' matches 'str'. Also returns the match score in
- * 'outScore' and the matching character positions in 'matches'.
+ * Returns TRUE if "pat_arg" matches "str". Also returns the match score in
+ * "outScore" and the matching character positions in "matches".
*/
int
fuzzy_match(
diff --git a/src/testdir/test_matchfuzzy.vim b/src/testdir/test_matchfuzzy.vim
index 502d136..43eca8f 100644
--- a/src/testdir/test_matchfuzzy.vim
+++ b/src/testdir/test_matchfuzzy.vim
@@ -2,6 +2,7 @@
source shared.vim
source check.vim
+source term_util.vim
" Test for matchfuzzy()
func Test_matchfuzzy()
@@ -253,4 +254,30 @@ func Test_matchfuzzy_limit()
call assert_equal([{'id': 5, 'val': 'crayon'}], l->matchfuzzy('c', #{key: 'val', limit: 1}))
endfunc
+" This was using uninitialized memory
+func Test_matchfuzzy_initialized()
+ CheckRunVimInTerminal
+
+ " This can take a very long time (esp. when using valgrind). Run in a
+ " separate Vim instance and kill it after two seconds. We only check for
+ " memory errors.
+ let lines =<< trim END
+ lvimgrep [ss [fg*
+ END
+ call writefile(lines, 'XTest_matchfuzzy', 'D')
+
+ let buf = RunVimInTerminal('-u NONE -X -Z', {})
+ call term_sendkeys(buf, ":source XTest_matchfuzzy\n")
+ call TermWait(buf, 2000)
+
+ let job = term_getjob(buf)
+ if job_status(job) == "run"
+ call job_stop(job, "int")
+ call TermWait(buf, 50)
+ endif
+
+ " clean up
+ call StopVimInTerminal(buf)
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index c93499c..0e83a6f 100644
--- a/src/version.c
+++ b/src/version.c
@@ -695,6 +695,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1499,
/**/
1378,
/**/
|