mirror of
https://github.com/git/git.git
synced 2024-11-24 10:26:17 +08:00
common_prefix: simplify and fix scanning for prefixes
common_prefix() scans backwards from the far end of each 'next' pathspec, starting from 'len', shortening the 'prefix' using 'path' as a reference. However, there is a small opportunity for an out-of-bounds access because len is unconditionally set to prefix-1 after a "direct match" test failed. This means that if 'next' is shorter than prefix+2, we read past it. Instead of a minimal fix, simplify the loop: scan *forward* over the 'next' entry, remembering the last '/' where it matched the prefix known so far. This is far easier to read and also has the advantage that we only scan over each entry once. Acked-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
e0a9110176
commit
42f9852f3c
26
dir.c
26
dir.c
@ -31,22 +31,22 @@ static int common_prefix(const char **pathspec)
|
||||
if (!slash)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The first 'prefix' characters of 'path' are common leading
|
||||
* path components among the pathspecs we have seen so far,
|
||||
* including the trailing slash.
|
||||
*/
|
||||
prefix = slash - path + 1;
|
||||
while ((next = *++pathspec) != NULL) {
|
||||
int len = strlen(next);
|
||||
if (len >= prefix && !memcmp(path, next, prefix))
|
||||
int len, last_matching_slash = -1;
|
||||
for (len = 0; len < prefix && next[len] == path[len]; len++)
|
||||
if (next[len] == '/')
|
||||
last_matching_slash = len;
|
||||
if (len == prefix)
|
||||
continue;
|
||||
len = prefix - 1;
|
||||
for (;;) {
|
||||
if (!len)
|
||||
return 0;
|
||||
if (next[--len] != '/')
|
||||
continue;
|
||||
if (memcmp(path, next, len+1))
|
||||
continue;
|
||||
prefix = len + 1;
|
||||
break;
|
||||
}
|
||||
if (last_matching_slash < 0)
|
||||
return 0;
|
||||
prefix = last_matching_slash + 1;
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user