Skip to content

Commit

Permalink
Merge branch 'mmap-regexec'
Browse files Browse the repository at this point in the history
This topic branch fixes a segmentation fault when using `-G` or `-S
--pickaxe-regex` with `git diff` on new-born files that are configured
without user diff drivers, and that hence get mmap()ed into memory.

Signed-off-by: Johannes Schindelin <[email protected]>
  • Loading branch information
Git for Windows Build Agent committed Sep 13, 2016
2 parents 219c185 + eb74afa commit c01971e
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 20 deletions.
3 changes: 2 additions & 1 deletion diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,8 @@ static int find_word_boundaries(mmfile_t *buffer, regex_t *word_regex,
{
if (word_regex && *begin < buffer->size) {
regmatch_t match[1];
if (!regexec(word_regex, buffer->ptr + *begin, 1, match, 0)) {
if (!regexec_buf(word_regex, buffer->ptr + *begin,
buffer->size - *begin, 1, match, 0)) {
char *p = memchr(buffer->ptr + *begin + match[0].rm_so,
'\n', match[0].rm_eo - match[0].rm_so);
*end = p ? p - buffer->ptr : match[0].rm_eo + *begin;
Expand Down
18 changes: 8 additions & 10 deletions diffcore-pickaxe.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)
{
struct diffgrep_cb *data = priv;
regmatch_t regmatch;
int hold;

if (line[0] != '+' && line[0] != '-')
return;
Expand All @@ -33,11 +32,8 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)
* caller early.
*/
return;
/* Yuck -- line ought to be "const char *"! */
hold = line[len];
line[len] = '\0';
data->hit = !regexec(data->regexp, line + 1, 1, &regmatch, 0);
line[len] = hold;
data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1,
&regmatch, 0);
}

static int diff_grep(mmfile_t *one, mmfile_t *two,
Expand All @@ -50,9 +46,11 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
xdemitconf_t xecfg;

if (!one)
return !regexec(regexp, two->ptr, 1, &regmatch, 0);
return !regexec_buf(regexp, two->ptr, two->size,
1, &regmatch, 0);
if (!two)
return !regexec(regexp, one->ptr, 1, &regmatch, 0);
return !regexec_buf(regexp, one->ptr, one->size,
1, &regmatch, 0);

/*
* We have both sides; need to run textual diff and see if
Expand Down Expand Up @@ -83,8 +81,8 @@ static unsigned int contains(mmfile_t *mf, regex_t *regexp, kwset_t kws)
regmatch_t regmatch;
int flags = 0;

assert(data[sz] == '\0');
while (*data && !regexec(regexp, data, 1, &regmatch, flags)) {
while (*data &&
!regexec_buf(regexp, data, sz, 1, &regmatch, flags)) {
flags |= REG_NOTBOL;
data += regmatch.rm_eo;
if (*data && regmatch.rm_so == regmatch.rm_eo)
Expand Down
21 changes: 21 additions & 0 deletions git-compat-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,27 @@ void git_qsort(void *base, size_t nmemb, size_t size,
#define qsort git_qsort
#endif

static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size,
size_t nmatch, regmatch_t pmatch[], int eflags)
{
#ifdef REG_STARTEND
assert(nmatch > 0 && pmatch);
pmatch[0].rm_so = 0;
pmatch[0].rm_eo = size;
return regexec(preg, buf, nmatch, pmatch, eflags | REG_STARTEND);
#else
char *buf2 = xmalloc(size + 1);
int ret;

memcpy(buf2, buf, size);
buf2[size] = '\0';
ret = regexec(preg, buf2, nmatch, pmatch, eflags);
free(buf2);

return ret;
#endif
}

#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
# define FORCE_DIR_SET_GID S_ISGID
#else
Expand Down
22 changes: 22 additions & 0 deletions t/t4061-diff-pickaxe.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh
#
# Copyright (c) 2016 Johannes Schindelin
#

test_description='Pickaxe options'

. ./test-lib.sh

test_expect_success setup '
test_commit initial &&
printf "%04096d" 0 >4096-zeroes.txt &&
git add 4096-zeroes.txt &&
test_tick &&
git commit -m "A 4k file"
'
test_expect_success '-G matches' '
git diff --name-only -G "^0{4096}$" HEAD^ >out &&
test 4096-zeroes.txt = "$(cat out)"
'

test_done
13 changes: 4 additions & 9 deletions xdiff-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,10 @@ struct ff_regs {
static long ff_regexp(const char *line, long len,
char *buffer, long buffer_size, void *priv)
{
char *line_buffer;
struct ff_regs *regs = priv;
regmatch_t pmatch[2];
int i;
int result = -1;
int result;

/* Exclude terminating newline (and cr) from matching */
if (len > 0 && line[len-1] == '\n') {
Expand All @@ -228,18 +227,16 @@ static long ff_regexp(const char *line, long len,
len--;
}

line_buffer = xstrndup(line, len); /* make NUL terminated */

for (i = 0; i < regs->nr; i++) {
struct ff_reg *reg = regs->array + i;
if (!regexec(&reg->re, line_buffer, 2, pmatch, 0)) {
if (!regexec_buf(&reg->re, line, len, 2, pmatch, 0)) {
if (reg->negate)
goto fail;
return -1;
break;
}
}
if (regs->nr <= i)
goto fail;
return -1;
i = pmatch[1].rm_so >= 0 ? 1 : 0;
line += pmatch[i].rm_so;
result = pmatch[i].rm_eo - pmatch[i].rm_so;
Expand All @@ -248,8 +245,6 @@ static long ff_regexp(const char *line, long len,
while (result > 0 && (isspace(line[result - 1])))
result--;
memcpy(buffer, line, result);
fail:
free(line_buffer);
return result;
}

Expand Down

0 comments on commit c01971e

Please sign in to comment.