regex: do not call `regfree()` if compilation fails
authorMartin Ågren <martin.agren@gmail.com>
Sun, 20 May 2018 10:50:32 +0000 (12:50 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 21 May 2018 04:58:32 +0000 (13:58 +0900)
It is apparently undefined behavior to call `regfree()` on a regex where
`regcomp()` failed. The language in [1] is a bit muddy, at least to me,
but the clearest hint is this (`preg` is the `regex_t *`):

Upon successful completion, the regcomp() function shall return 0.
Otherwise, it shall return an integer value indicating an error as
described in <regex.h>, and the content of preg is undefined.

Funnily enough, there is also the `regerror()` function which should be
given a pointer to such a "failed" `regex_t` -- the content of which
would supposedly be undefined -- and which may investigate it to come up
with a detailed error message.

In any case, the example in that document shows how `regfree()` is not
called after `regcomp()` fails.

We have quite a few users of this API and most get this right. These
three users do not.

Several implementations can handle this just fine [2] and these code paths
supposedly have not wreaked havoc or we'd have heard about it. (These
are all in code paths where git got bad input and is just about to die
anyway.) But let's just avoid the issue altogether.

[1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/regcomp.html

[2] https://www.redhat.com/archives/libvir-list/2013-September/msg00262.html

Researched-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-byi Martin Ågren <martin.agren@gmail.com>

Signed-off-by: Junio C Hamano <gitster@pobox.com>
diffcore-pickaxe.c
grep.c
index 239ce5122b3a45bec211e0c20113385c0e37805d..800a899c8621eaeba7f4246139df0f289ceb6ee2 100644 (file)
@@ -215,7 +215,6 @@ static void regcomp_or_die(regex_t *regex, const char *needle, int cflags)
                /* The POSIX.2 people are surely sick */
                char errbuf[1024];
                regerror(err, regex, errbuf, 1024);
-               regfree(regex);
                die("invalid regex: %s", errbuf);
        }
 }
diff --git a/grep.c b/grep.c
index 834b8eb439297ff5af4a3da8b946a40ca68057f1..35fccf9aba4ceaec944acb11308658869c638308 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -636,7 +636,6 @@ static void compile_fixed_regexp(struct grep_pat *p, struct grep_opt *opt)
        if (err) {
                char errbuf[1024];
                regerror(err, &p->regexp, errbuf, sizeof(errbuf));
-               regfree(&p->regexp);
                compile_regexp_failed(p, errbuf);
        }
 }
@@ -701,7 +700,6 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt)
        if (err) {
                char errbuf[1024];
                regerror(err, &p->regexp, errbuf, 1024);
-               regfree(&p->regexp);
                compile_regexp_failed(p, errbuf);
        }
 }