Merge branch 'rs/apply-fuzzy-match-fix' into maint

A fix for an ancient bug in "git apply --ignore-space-change" codepath.

* rs/apply-fuzzy-match-fix:
  apply: avoid out-of-bounds access in fuzzy_matchlines()
This commit is contained in:
Junio C Hamano 2017-11-27 10:57:02 +09:00
commit df481b99ef

57
apply.c
View file

@ -305,52 +305,33 @@ static uint32_t hash_line(const char *cp, size_t len)
static int fuzzy_matchlines(const char *s1, size_t n1, static int fuzzy_matchlines(const char *s1, size_t n1,
const char *s2, size_t n2) const char *s2, size_t n2)
{ {
const char *last1 = s1 + n1 - 1; const char *end1 = s1 + n1;
const char *last2 = s2 + n2 - 1; const char *end2 = s2 + n2;
int result = 0;
/* ignore line endings */ /* ignore line endings */
while ((*last1 == '\r') || (*last1 == '\n')) while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
last1--; end1--;
while ((*last2 == '\r') || (*last2 == '\n')) while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
last2--; end2--;
/* skip leading whitespaces, if both begin with whitespace */ while (s1 < end1 && s2 < end2) {
if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) { if (isspace(*s1)) {
while (isspace(*s1) && (s1 <= last1)) /*
s1++; * Skip whitespace. We check on both buffers
while (isspace(*s2) && (s2 <= last2)) * because we don't want "a b" to match "ab".
s2++; */
} if (!isspace(*s2))
/* early return if both lines are empty */ return 0;
if ((s1 > last1) && (s2 > last2)) while (s1 < end1 && isspace(*s1))
return 1;
while (!result) {
result = *s1++ - *s2++;
/*
* Skip whitespace inside. We check for whitespace on
* both buffers because we don't want "a b" to match
* "ab"
*/
if (isspace(*s1) && isspace(*s2)) {
while (isspace(*s1) && s1 <= last1)
s1++; s1++;
while (isspace(*s2) && s2 <= last2) while (s2 < end2 && isspace(*s2))
s2++; s2++;
} } else if (*s1++ != *s2++)
/*
* If we reached the end on one side only,
* lines don't match
*/
if (
((s2 > last2) && (s1 <= last1)) ||
((s1 > last1) && (s2 <= last2)))
return 0; return 0;
if ((s1 > last1) && (s2 > last2))
break;
} }
return !result; /* If we reached the end on one side only, lines don't match. */
return s1 == end1 && s2 == end2;
} }
static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag) static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)