Skip to content

Commit 6ce15ce

Browse files
rscharfegitster
authored andcommitted
apply: avoid out-of-bounds access in fuzzy_matchlines()
fuzzy_matchlines() uses a pointers to the first and last characters of two lines to keep track while matching them. This makes it impossible to deal with empty strings. It accesses characters before the start of empty lines. It can also access characters after the end when checking for trailing whitespace in the main loop. Avoid that by using pointers to the first character and the one *after* the last one. This is well-defined as long as the latter is not dereferenced. Basically rewrite the function based on that premise; it becomes much simpler as a result. There is no need to check for leading whitespace outside of the main loop anymore. Reported-by: Mahmoud Al-Qudsi <[email protected]> Signed-off-by: Rene Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 39aaab1 commit 6ce15ce

File tree

1 file changed

+20
-39
lines changed

1 file changed

+20
-39
lines changed

apply.c

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -303,52 +303,33 @@ static uint32_t hash_line(const char *cp, size_t len)
303303
static int fuzzy_matchlines(const char *s1, size_t n1,
304304
const char *s2, size_t n2)
305305
{
306-
const char *last1 = s1 + n1 - 1;
307-
const char *last2 = s2 + n2 - 1;
308-
int result = 0;
306+
const char *end1 = s1 + n1;
307+
const char *end2 = s2 + n2;
309308

310309
/* ignore line endings */
311-
while ((*last1 == '\r') || (*last1 == '\n'))
312-
last1--;
313-
while ((*last2 == '\r') || (*last2 == '\n'))
314-
last2--;
315-
316-
/* skip leading whitespaces, if both begin with whitespace */
317-
if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) {
318-
while (isspace(*s1) && (s1 <= last1))
319-
s1++;
320-
while (isspace(*s2) && (s2 <= last2))
321-
s2++;
322-
}
323-
/* early return if both lines are empty */
324-
if ((s1 > last1) && (s2 > last2))
325-
return 1;
326-
while (!result) {
327-
result = *s1++ - *s2++;
328-
/*
329-
* Skip whitespace inside. We check for whitespace on
330-
* both buffers because we don't want "a b" to match
331-
* "ab"
332-
*/
333-
if (isspace(*s1) && isspace(*s2)) {
334-
while (isspace(*s1) && s1 <= last1)
310+
while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
311+
end1--;
312+
while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
313+
end2--;
314+
315+
while (s1 < end1 && s2 < end2) {
316+
if (isspace(*s1)) {
317+
/*
318+
* Skip whitespace. We check on both buffers
319+
* because we don't want "a b" to match "ab".
320+
*/
321+
if (!isspace(*s2))
322+
return 0;
323+
while (s1 < end1 && isspace(*s1))
335324
s1++;
336-
while (isspace(*s2) && s2 <= last2)
325+
while (s2 < end2 && isspace(*s2))
337326
s2++;
338-
}
339-
/*
340-
* If we reached the end on one side only,
341-
* lines don't match
342-
*/
343-
if (
344-
((s2 > last2) && (s1 <= last1)) ||
345-
((s1 > last1) && (s2 <= last2)))
327+
} else if (*s1++ != *s2++)
346328
return 0;
347-
if ((s1 > last1) && (s2 > last2))
348-
break;
349329
}
350330

351-
return !result;
331+
/* If we reached the end on one side only, lines don't match. */
332+
return s1 == end1 && s2 == end2;
352333
}
353334

354335
static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)

0 commit comments

Comments
 (0)