diff mbox series

[12/20] http-backend.c: fix cmd_main() memory leak, refactor reg{exec,free}()

Message ID patch-12.20-9be5b0c7836-20221228T175512Z-avarab@gmail.com (mailing list archive)
State Superseded
Headers show
Series leak fixes: various simple leak fixes | expand

Commit Message

Ævar Arnfjörð Bjarmason Dec. 28, 2022, 6 p.m. UTC
Fix a memory leak that's been with us ever since
2f4038ab337 (Git-aware CGI to provide dumb HTTP transport,
2009-10-30). In this case we're not calling regerror() after a failed
regexec(), and don't otherwise use "re" afterwards.

We can therefore simplify this code by calling regfree() right after
the regexec(). An alternative fix would be to add a regfree() to both
the "return" and "break" path in this for-loop.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 http-backend.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

Comments

René Scharfe Dec. 28, 2022, 9:37 p.m. UTC | #1
Am 28.12.22 um 19:00 schrieb Ævar Arnfjörð Bjarmason:
> Fix a memory leak that's been with us ever since
> 2f4038ab337 (Git-aware CGI to provide dumb HTTP transport,
> 2009-10-30). In this case we're not calling regerror() after a failed
> regexec(), and don't otherwise use "re" afterwards.
>
> We can therefore simplify this code by calling regfree() right after
> the regexec(). An alternative fix would be to add a regfree() to both
> the "return" and "break" path in this for-loop.

Yes, or to add one regfree() call early in the conditional...

>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  http-backend.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/http-backend.c b/http-backend.c
> index 6eb3b2fe51c..9bb63c458b1 100644
> --- a/http-backend.c
> +++ b/http-backend.c
> @@ -759,10 +759,14 @@ int cmd_main(int argc, const char **argv)
>  		struct service_cmd *c = &services[i];
>  		regex_t re;
>  		regmatch_t out[1];
> +		int ret;
>
>  		if (regcomp(&re, c->pattern, REG_EXTENDED))
>  			die("Bogus regex in service table: %s", c->pattern);
> -		if (!regexec(&re, dir, 1, out, 0)) {
> +		ret = regexec(&re, dir, 1, out, 0);
> +		regfree(&re);
> +
> +		if (!ret) {
>  			size_t n;
>

... i.e. right here.  But only after copying the offsets out of "out"!

Anyway, the ret approach taken here is fine.

"dir" is still leaking, by the way.  Probably worth a separate patch.

>  			if (strcmp(method, c->method))
> @@ -774,7 +778,6 @@ int cmd_main(int argc, const char **argv)
>  			dir[out[0].rm_so] = 0;
>  			break;
>  		}
> -		regfree(&re);
>  	}
>
>  	if (!cmd)
Junio C Hamano Dec. 29, 2022, 7:32 a.m. UTC | #2
René Scharfe <l.s.r@web.de> writes:

>> diff --git a/http-backend.c b/http-backend.c
>> index 6eb3b2fe51c..9bb63c458b1 100644
>> --- a/http-backend.c
>> +++ b/http-backend.c
>> @@ -759,10 +759,14 @@ int cmd_main(int argc, const char **argv)
>>  		struct service_cmd *c = &services[i];
>>  		regex_t re;
>>  		regmatch_t out[1];
>> +		int ret;
>>
>>  		if (regcomp(&re, c->pattern, REG_EXTENDED))
>>  			die("Bogus regex in service table: %s", c->pattern);
>> -		if (!regexec(&re, dir, 1, out, 0)) {
>> +		ret = regexec(&re, dir, 1, out, 0);
>> +		regfree(&re);
>> +
>> +		if (!ret) {
>>  			size_t n;
>>
>
> ... i.e. right here.  But only after copying the offsets out of "out"!

"only after..."?  Do out[i].rm_eo and out[i].rm_so become invalid
after calling regfree() on the regex out[] was taken against?  I do
not think so, and am confused by the comment.  After all, if we can
free only after copying the offsets out of "out", the posted patch
in question is already wrong ;-)

> Anyway, the ret approach taken here is fine.

Yup.

> "dir" is still leaking, by the way.  Probably worth a separate patch.

Good eyes.  But I'd actually say UNLEAK() is fine for that one.

Thanks.
René Scharfe Dec. 29, 2022, 3:49 p.m. UTC | #3
Am 29.12.22 um 08:32 schrieb Junio C Hamano:
> René Scharfe <l.s.r@web.de> writes:
>
>>> diff --git a/http-backend.c b/http-backend.c
>>> index 6eb3b2fe51c..9bb63c458b1 100644
>>> --- a/http-backend.c
>>> +++ b/http-backend.c
>>> @@ -759,10 +759,14 @@ int cmd_main(int argc, const char **argv)
>>>  		struct service_cmd *c = &services[i];
>>>  		regex_t re;
>>>  		regmatch_t out[1];
>>> +		int ret;
>>>
>>>  		if (regcomp(&re, c->pattern, REG_EXTENDED))
>>>  			die("Bogus regex in service table: %s", c->pattern);
>>> -		if (!regexec(&re, dir, 1, out, 0)) {
>>> +		ret = regexec(&re, dir, 1, out, 0);
>>> +		regfree(&re);
>>> +
>>> +		if (!ret) {
>>>  			size_t n;
>>>
>>
>> ... i.e. right here.  But only after copying the offsets out of "out"!
>
> "only after..."?  Do out[i].rm_eo and out[i].rm_so become invalid
> after calling regfree() on the regex out[] was taken against?  I do
> not think so, and am confused by the comment.
Nah, sorry, I was confused. o_O  "out" is not affected by regfree(), of
course; it's supplied by the regexec() caller -- cmd_main() owns it.

René
diff mbox series

Patch

diff --git a/http-backend.c b/http-backend.c
index 6eb3b2fe51c..9bb63c458b1 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -759,10 +759,14 @@  int cmd_main(int argc, const char **argv)
 		struct service_cmd *c = &services[i];
 		regex_t re;
 		regmatch_t out[1];
+		int ret;
 
 		if (regcomp(&re, c->pattern, REG_EXTENDED))
 			die("Bogus regex in service table: %s", c->pattern);
-		if (!regexec(&re, dir, 1, out, 0)) {
+		ret = regexec(&re, dir, 1, out, 0);
+		regfree(&re);
+
+		if (!ret) {
 			size_t n;
 
 			if (strcmp(method, c->method))
@@ -774,7 +778,6 @@  int cmd_main(int argc, const char **argv)
 			dir[out[0].rm_so] = 0;
 			break;
 		}
-		regfree(&re);
 	}
 
 	if (!cmd)