From: Junio C Hamano Date: Tue, 15 Jun 2010 23:02:03 +0000 (+0200) Subject: common_prefix: simplify and fix scanning for prefixes X-Git-Tag: v1.7.2-rc0~10^2 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=42f9852f3c7476b5608ad297443e6d459516f8c0;p=git.git 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 Signed-off-by: Junio C Hamano --- diff --git a/dir.c b/dir.c index 5615f33af..7f912c76f 100644 --- a/dir.c +++ b/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; }