зеркало из https://github.com/microsoft/git.git
Merge branch 'js/regexec-buf' into maint
Some codepaths in "git diff" used regexec(3) on a buffer that was mmap(2)ed, which may not have a terminating NUL, leading to a read beyond the end of the mapped region. This was fixed by introducing a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND extension. * js/regexec-buf: regex: use regexec_buf() regex: add regexec_buf() that can work on a non NUL-terminated string regex: -G<pattern> feeds a non NUL-terminated string to regexec() and fails
This commit is contained in:
Коммит
300e95f7df
3
Makefile
3
Makefile
|
@ -301,7 +301,8 @@ all::
|
|||
# crashes due to allocation and free working on different 'heaps'.
|
||||
# It's defined automatically if USE_NED_ALLOCATOR is set.
|
||||
#
|
||||
# Define NO_REGEX if you have no or inferior regex support in your C library.
|
||||
# Define NO_REGEX if your C library lacks regex support with REG_STARTEND
|
||||
# feature.
|
||||
#
|
||||
# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
|
||||
# user.
|
||||
|
|
3
diff.c
3
diff.c
|
@ -949,7 +949,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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -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, ®match, 0);
|
||||
line[len] = hold;
|
||||
data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1,
|
||||
®match, 0);
|
||||
}
|
||||
|
||||
static int diff_grep(mmfile_t *one, mmfile_t *two,
|
||||
|
@ -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, ®match, 0);
|
||||
return !regexec_buf(regexp, two->ptr, two->size,
|
||||
1, ®match, 0);
|
||||
if (!two)
|
||||
return !regexec(regexp, one->ptr, 1, ®match, 0);
|
||||
return !regexec_buf(regexp, one->ptr, one->size,
|
||||
1, ®match, 0);
|
||||
|
||||
/*
|
||||
* We have both sides; need to run textual diff and see if
|
||||
|
@ -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, ®match, flags)) {
|
||||
while (*data &&
|
||||
!regexec_buf(regexp, data, sz, 1, ®match, flags)) {
|
||||
flags |= REG_NOTBOL;
|
||||
data += regmatch.rm_eo;
|
||||
if (*data && regmatch.rm_so == regmatch.rm_eo)
|
||||
|
|
|
@ -974,6 +974,19 @@ void git_qsort(void *base, size_t nmemb, size_t size,
|
|||
#define qsort git_qsort
|
||||
#endif
|
||||
|
||||
#ifndef REG_STARTEND
|
||||
#error "Git requires REG_STARTEND support. Compile with NO_REGEX=NeedsStartEnd"
|
||||
#endif
|
||||
|
||||
static inline int regexec_buf(const regex_t *preg, const char *buf, size_t size,
|
||||
size_t nmatch, regmatch_t pmatch[], int eflags)
|
||||
{
|
||||
assert(nmatch > 0 && pmatch);
|
||||
pmatch[0].rm_so = 0;
|
||||
pmatch[0].rm_eo = size;
|
||||
return regexec(preg, buf, nmatch, pmatch, eflags | REG_STARTEND);
|
||||
}
|
||||
|
||||
#ifndef DIR_HAS_BSD_GROUP_SEMANTICS
|
||||
# define FORCE_DIR_SET_GID S_ISGID
|
||||
#else
|
||||
|
|
14
grep.c
14
grep.c
|
@ -898,17 +898,6 @@ static int fixmatch(struct grep_pat *p, char *line, char *eol,
|
|||
}
|
||||
}
|
||||
|
||||
static int regmatch(const regex_t *preg, char *line, char *eol,
|
||||
regmatch_t *match, int eflags)
|
||||
{
|
||||
#ifdef REG_STARTEND
|
||||
match->rm_so = 0;
|
||||
match->rm_eo = eol - line;
|
||||
eflags |= REG_STARTEND;
|
||||
#endif
|
||||
return regexec(preg, line, 1, match, eflags);
|
||||
}
|
||||
|
||||
static int patmatch(struct grep_pat *p, char *line, char *eol,
|
||||
regmatch_t *match, int eflags)
|
||||
{
|
||||
|
@ -919,7 +908,8 @@ static int patmatch(struct grep_pat *p, char *line, char *eol,
|
|||
else if (p->pcre_regexp)
|
||||
hit = !pcrematch(p, line, eol, match, eflags);
|
||||
else
|
||||
hit = !regmatch(&p->regexp, line, eol, match, eflags);
|
||||
hit = !regexec_buf(&p->regexp, line, eol - line, 1, match,
|
||||
eflags);
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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') {
|
||||
|
@ -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(®->re, line_buffer, 2, pmatch, 0)) {
|
||||
if (!regexec_buf(®->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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче