gpg-interface.c: Fix potentially freeing NULL values
PATCH 1/1 gpg-interface.c: Fix potentially freeing NULL values
Fix signature_check_clear() to free only values that are non-NULL. This especially applies to 'key' and 'signer' members that can be NULL during normal operations, depending on exact GnuPG output. While at it, also allow other members to be NULL to make the function easier to use, even if there is no real need to account for that right now.
--- gpg-interface.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
gpg-interface.c +10 -5
@@ -15,9 +15,14 @@ static const char *gpg_program = "gpg";void signature_check_clear (struct signature_check *sigc) { -FREE_AND_NULL (sigc->payload); -FREE_AND_NULL (sigc->gpg_output); -FREE_AND_NULL (sigc->gpg_status); -FREE_AND_NULL (sigc->signer); -FREE_AND_NULL (sigc->key); +if (sigc->payload) +FREE_AND_NULL (sigc->payload); +if (sigc->gpg_output) +FREE_AND_NULL (sigc->gpg_output); +if (sigc->gpg_status) +FREE_AND_NULL (sigc->gpg_status); +if (sigc->signer) +FREE_AND_NULL (sigc->signer); +if (sigc->key) +FREE_AND_NULL (sigc->key); }
Signature · 1 line
2.18.0
Quoted 5 lines · Michał Górny
Fix
signature_check_clear()to free only values that are non-NULL. This especially applies to 'key' and 'signer' members that can be NULL during normal operations, depending on exact GnuPG output. While at it, also allow other members to be NULL to make the function easier to use, even if there is no real need to account for that right now.
free(NULL) is valid behavior[1] and much of the Git codebase relies upon it.
Did you run into a case where it misbehaved?
[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html
Quoted 25 lines
Signed-off-by Michał Górny <[email protected]>---
gpg-interface.c +10
-5@@ -15,9 +15,14 @@ static const char *gpg_program = "gpg";void signature_check_clear (struct signature_check *sigc) { -FREE_AND_NULL (sigc->payload); -FREE_AND_NULL (sigc->gpg_output); -FREE_AND_NULL (sigc->gpg_status); -FREE_AND_NULL (sigc->signer); -FREE_AND_NULL (sigc->key); +if (sigc->payload) +FREE_AND_NULL (sigc->payload); +if (sigc->gpg_output) +FREE_AND_NULL (sigc->gpg_output); +if (sigc->gpg_status) +FREE_AND_NULL (sigc->gpg_status); +if (sigc->signer) +FREE_AND_NULL (sigc->signer); +if (sigc->key) +FREE_AND_NULL (sigc->key); }
Quoted 10 lines · Eric Sunshine
Quoted 5 lines · Michał Górny
Fix
signature_check_clear()to free only values that are non-NULL. This especially applies to 'key' and 'signer' members that can be NULL during normal operations, depending on exact GnuPG output. While at it, also allow other members to be NULL to make the function easier to use, even if there is no real need to account for that right now.free(NULL) is valid behavior[1] and much of the Git codebase relies upon it.
Did you run into a case where it misbehaved?
Nope. I was actually wondering if it's expected, so I did a quick grep to check whether git is checking pointers for non-NULL before free()ing, and found at least one:
blame.c-static void drop_origin_blob(struct blame_origin *o) blame.c-{
blame.c- if (o->file.ptr) {blame.c: FREE_AND_NULL(o->file.ptr);
blame.c- }
blame.c-}
So I wrongly presumed it might be desirable. If it's not, that's fine by me.
Quoted 28 lines
[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html
Quoted 25 lines
Signed-off-by Michał Górny <[email protected]>---
gpg-interface.c +10
-5@@ -15,9 +15,14 @@ static const char *gpg_program = "gpg";void signature_check_clear (struct signature_check *sigc) { -FREE_AND_NULL (sigc->payload); -FREE_AND_NULL (sigc->gpg_output); -FREE_AND_NULL (sigc->gpg_status); -FREE_AND_NULL (sigc->signer); -FREE_AND_NULL (sigc->key); +if (sigc->payload) +FREE_AND_NULL (sigc->payload); +if (sigc->gpg_output) +FREE_AND_NULL (sigc->gpg_output); +if (sigc->gpg_status) +FREE_AND_NULL (sigc->gpg_status); +if (sigc->signer) +FREE_AND_NULL (sigc->signer); +if (sigc->key) +FREE_AND_NULL (sigc->key); }
Signature · 2 lines
Best regards, Michał Górny
PATCH 1/1 refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Change the few conditional uses of FREE_AND_NULL(x) to be unconditional. As noted in the standard[1] free(NULL) is perfectly valid, so we might as well leave this check up to the C library.
1. http://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html
---
Let's do the opposite of this instead.
blame.c | 4 +--- branch.c | 4 +--- http.c | 4 +--- tree-diff.c | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-)
blame.c +1 -3
@@ -334,9 +334,7 @@ static void fill_origin_blob(struct diff_options *opt,static void drop_origin_blob (struct blame_origin *o) { -if (o->file.ptr) { -FREE_AND_NULL (o->file.ptr); - } +FREE_AND_NULL (o->file.ptr); }/*
branch.c +1 -3
@@ -25,9 +25,7 @@ static int find_tracked_branch(struct remote *remote, void *priv) tracking->remote = remote->name; }else {free (tracking->spec.src); -if (tracking->src) { -FREE_AND_NULL (tracking->src); - } +FREE_AND_NULL (tracking->src); } tracking->spec.src =NULL ; }
http.c +1 -3
@@ -2418,9 +2418,7 @@ void release_http_object_request(struct http_object_request *freq)close (freq->localfile); freq->localfile =-1 ; } -if (freq->url !=NULL ) { -FREE_AND_NULL (freq->url); - } +FREE_AND_NULL (freq->url);if (freq->slot !=NULL ) { freq->slot->callback_func =NULL ; freq->slot->callback_data =NULL ;
tree-diff.c +1 -3
@@ -557,9 +557,7 @@ struct combine_diff_path *diff_tree_paths(* free pre-allocated last element, if any * (see path_appendnew() for details about why) */ -if (p->next) { -FREE_AND_NULL (p->next); - } +FREE_AND_NULL (p->next);return p; }
Signature · 1 line
2.18.0.865.gffc8e1a3cd6
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 4 lines · Ævar Arnfjörð Bjarmason
Change the few conditional uses of
FREE_AND_NULL(x)to be unconditional. As noted in the standard[1] free(NULL) is perfectly valid, so we might as well leave this check up to the C library.
I'm not trying to make you work more on this. But out of curiosity would coccinelle help catch this pattern? Szeder's recent work on running cocci automatically would help catch all future code like this if we could write an spatch.
Signature · 1 line
Duy
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 11 lines · Duy Nguyen
Quoted 4 lines · Ævar Arnfjörð Bjarmason
Change the few conditional uses of
FREE_AND_NULL(x)to be unconditional. As noted in the standard[1] free(NULL) is perfectly valid, so we might as well leave this check up to the C library.I'm not trying to make you work more on this. But out of curiosity would coccinelle help catch this pattern? Szeder's recent work on running cocci automatically would help catch all future code like this if we could write an spatch.
Just fyi this seems to do the trick. Although I'm nowhere good at coccinelle to say if we should include this (or something like it)
-- 8< --
contrib/coccinelle/free.cocci +6 -0
@@ -16,3 +16,9 @@ expression E; - free(E); + FREE_AND_NULL(E); - E = NULL; + +@@ +expression E; +@@ +- if (E) { FREE_AND_NULL(E); } ++ FREE_AND_NULL(E);
-- 8< --
--
Duy
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 9 lines · Duy Nguyen
Just fyi this seems to do the trick. Although I'm nowhere good at coccinelle to say if we should include this (or something like it)
-- 8< --
contrib/coccinelle/free.cocci +0
-0
contrib/coccinelle/free.cocci expression E; · line 24
Quoted 9 lines
contrib/coccinelle/free.cocci +6
-0@@ -16,3 +16,9 @@ expression E; - free(E); + FREE_AND_NULL(E); - E = NULL; + +@@ +expression E; +@@ +- if (E) { FREE_AND_NULL(E); } ++ FREE_AND_NULL(E);
It is a bit sad that
- if (E) FREE_AND_NULL(E);
is not sufficient to catch it. Shouldn't we be doing the same for regular free(E) as well? IOW, like the attached patch.
contrib/coccinelle/free.cocci | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
contrib/coccinelle/free.cocci +24 -0
@@ -16,3 +16,27 @@ expression E; - free(E); + FREE_AND_NULL(E); - E = NULL; + +@@ +expression E; +@@ +- if (E) + FREE_AND_NULL(E); + +@@ +expression E; +@@ +- if (E) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (!E) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (E) { FREE_AND_NULL(E); } ++ FREE_AND_NULL(E);
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 8 lines · Junio C Hamano
It is a bit sad that
- if (E) FREE_AND_NULL(E);is not sufficient to catch it. Shouldn't we be doing the same for regular free(E) as well? IOW, like the attached patch.
...
And revised even more to also spell "E" as "E != NULL" (and "!E" as "E == NULL"), which seems to make a difference, which is even more sad. I do not want to wonder if I have to also add "NULL == E" and other variants, so I'll stop here.
contrib/coccinelle/free.cocci | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
contrib/coccinelle/free.cocci +60 -0
@@ -16,3 +16,63 @@ expression E; - free(E); + FREE_AND_NULL(E); - E = NULL; + +@@ +expression E; +@@ +- if (E) + FREE_AND_NULL(E); + +@@ +expression E; +@@ +- if (E != NULL) + free(E); + +@@ +expression E; +@@ +- if (E == NULL) + free(E); + +@@ +expression E; +@@ +- if (E != NULL) + FREE_AND_NULL(E); + +@@ +expression E; +@@ +- if (E) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (!E) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (E) { FREE_AND_NULL(E); } ++ FREE_AND_NULL(E); + +@@ +expression E; +@@ +- if (E != NULL) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (E == NULL) { free(E); } ++ free(E); + +@@ +expression E; +@@ +- if (E != NULL) { FREE_AND_NULL(E); } ++ FREE_AND_NULL(E);
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 7 lines · Junio C Hamano
Quoted 5 lines · Junio C Hamano
It is a bit sad that
- if (E) FREE_AND_NULL(E);
Quoted 8 lines
Quoted 3 lines
is not sufficient to catch it. Shouldn't we be doing the same for regular free(E) as well? IOW, like the attached patch.
...And revised even more to also spell "E" as "E != NULL" (and "!E" as "E == NULL"), which seems to make a difference, which is even more sad. I do not want to wonder if I have to also add "NULL == E" and other variants, so I'll stop here.
I think it makes sense that these are all distinct if you're using coccinelle to do stylistic transformations between them (e.g., enforcing curly braces even around one-liners).
I wonder if there is a way to "relax" a pattern where these semantically equivalent cases can all be covered automatically. I don't know enough about the tool to say.
I guess one way to do it would be to normalize the style in one rule (e.g., always "!E" instead of "E == NULL"), and then you only have to write the FREE_AND_NULL rule for the normalized form. For a single case like this, the end result is about the same number of rules, but in the long term it saves us work when we have a similar transformation.
-Peff
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 5 lines · Jeff King
Quoted 4 lines
And revised even more to also spell "E" as "E != NULL" (and "!E" as "E == NULL"), which seems to make a difference, which is even more sad. I do not want to wonder if I have to also add "NULL == E" and other variants, so I'll stop here.
Quoted 7 lines
I think it makes sense that these are all distinct if you're using coccinelle to do stylistic transformations between them (e.g., enforcing curly braces even around one-liners).
I wonder if there is a way to "relax" a pattern where these semantically equivalent cases can all be covered automatically. I don't know enough about the tool to say.
Hmm. They seem to call these "standard isomorphisms":
http://coccinelle.lip6.fr/standard.iso.html
but I'm not sure of the correct way to use them (e.g., if we want to apply them for matching but not actually transform the code, though I am not actually opposed to transforming the code, too).
-Peff
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
Quoted 11 lines · Jeff King
Quoted 3 lines
I wonder if there is a way to "relax" a pattern where these semantically equivalent cases can all be covered automatically. I don't know enough about the tool to say.
Hmm. They seem to call these "standard isomorphisms":
http://coccinelle.lip6.fr/standard.iso.html
but I'm not sure of the correct way to use them (e.g., if we want to apply them for matching but not actually transform the code, though I am not actually opposed to transforming the code, too).
Hmph, I should really pause before hitting 'send'. Last message, I promise. :)
I do not see an option to include a list an arbitrary set of isomorphisms, but the standard.iso list should be used by default. I wonder if you simply need to write your case in the normalized version they use there (which I think is "X == NULL"), and the others would be taken care of.
-Peff
Re: [PATCH] refactor various if (x) FREE_AND_NULL(x) to just FREE_AND_NULL(x)
In reply to Jeff KingQuoted 14 lines · Jeff King
Quoted 11 lines · Junio C Hamano
Quoted 8 lines · Junio C Hamano
It is a bit sad that
- if (E)
FREE_AND_NULL(E);is not sufficient to catch it. Shouldn't we be doing the same for regular free(E) as well? IOW, like the attached patch.
...
Quoted 8 lines
Quoted 4 lines
And revised even more to also spell "E" as "E != NULL" (and "!E" as "E == NULL"), which seems to make a difference, which is even more sad. I do not want to wonder if I have to also add "NULL == E" and other variants, so I'll stop here.
I think it makes sense that these are all distinct if you're using coccinelle to do stylistic transformations between them (e.g., enforcing curly braces even around one-liners).
Googling a bit shows a kernel patch [1]. Assuming that it works (I didn't check if it made it to linux.git) it would simplify our rules a bit.
[1] https://patchwork.kernel.org/patch/5167641/
Signature · 1 line
Duy