threads / patch / 59634

patch, 2 partsnotes: clean up confusing NULL checks in init_notes()

Subject: [PATCH 1/2] notes: clean up confusing NULL checks in init_notes()

## tl;dr

5 messages between Apr 22, 2023 and Apr 24, 2023. Diffs are folded; open one to read it.

replies: 4people: 2as markdown or json

Jeff King· Apr 22, 2023, 13:54 UTC · lore

[PATCH 0/2] coverity null-check fixes

Here are two cases I happened to notice via Coverity. Neither produces a user-visible bug; it's just slightly misleading code which can be cleaned up.

The first one is ancient, but since the nearby code changed, Coverity considered it new. :)

The second one is actually recent; I noted it already on the list, but it was already in 'next' at that point and is now in 'master'.

-Peff
Jeff King· Apr 22, 2023, 13:55 UTC · re: Jeff King · lore

Coverity complains that we check whether "notes_ref" is NULL, but it was already implied to be non-NULL earlier in the function. And this is true; since b9342b3fd63 (refs: add array of ref namespaces, 2022-08-05), we call xstrdup(notes_ref) unconditionally, which would segfault if it was NULL.

But that commit is actually doing the right thing. Even if NULL is
passed into the function, we'll use default_notes_ref() as a fallback,
which will never return NULL (it tries a few options, but its last
resort is a string literal). Ironically, the "!notes_ref" check was
added by the same commit that added the fallback: 709f79b0894 (Notes
API: init_notes(): Initialize the notes tree from the given notes ref,
2010-02-13). So this check never did anything.
Signed-off-by: Jeff King <peff@peff.net>
---
 notes.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to notes.c +2 −2
diff --git a/notes.c b/notes.c
index 45fb7f22d1..cadb435056 100644
--- a/notes.c
+++ b/notes.c
@@ -1019,13 +1019,13 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
 	t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
 	t->first_non_note = NULL;
 	t->prev_non_note = NULL;
-	t->ref = xstrdup_or_null(notes_ref);
+	t->ref = xstrdup(notes_ref);
 	t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
 	t->combine_notes = combine_notes;
 	t->initialized = 1;
 	t->dirty = 0;
 
-	if (flags & NOTES_INIT_EMPTY || !notes_ref ||
+	if (flags & NOTES_INIT_EMPTY ||
 	    repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
 		return;
 	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
-- 
2.40.0.653.g15ca972062
Junio C Hamano· Apr 24, 2023, 18:05 UTC · re: Jeff King · lore

Re: [PATCH 1/2] notes: clean up confusing NULL checks in init_notes()

Jeff King <peff@peff.net> writes:
Show 13 quoted lines
> Coverity complains that we check whether "notes_ref" is NULL, but it was
> already implied to be non-NULL earlier in the function. And this is
> true; since b9342b3fd63 (refs: add array of ref namespaces, 2022-08-05),
> we call xstrdup(notes_ref) unconditionally, which would segfault if it
> was NULL.
>
> But that commit is actually doing the right thing. Even if NULL is
> passed into the function, we'll use default_notes_ref() as a fallback,
> which will never return NULL (it tries a few options, but its last
> resort is a string literal). Ironically, the "!notes_ref" check was
> added by the same commit that added the fallback: 709f79b0894 (Notes
> API: init_notes(): Initialize the notes tree from the given notes ref,
> 2010-02-13). So this check never did anything.

I am impressed(?) that Coverity can complain at the "_or_null" part in xstrdup_or_null().

It all makes sense.  Thanks.
Show 25 quoted lines
> Signed-off-by: Jeff King <peff@peff.net>
> ---
>  notes.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/notes.c b/notes.c
> index 45fb7f22d1..cadb435056 100644
> --- a/notes.c
> +++ b/notes.c
> @@ -1019,13 +1019,13 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
>  	t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
>  	t->first_non_note = NULL;
>  	t->prev_non_note = NULL;
> -	t->ref = xstrdup_or_null(notes_ref);
> +	t->ref = xstrdup(notes_ref);
>  	t->update_ref = (flags & NOTES_INIT_WRITABLE) ? t->ref : NULL;
>  	t->combine_notes = combine_notes;
>  	t->initialized = 1;
>  	t->dirty = 0;
>  
> -	if (flags & NOTES_INIT_EMPTY || !notes_ref ||
> +	if (flags & NOTES_INIT_EMPTY ||
>  	    repo_get_oid_treeish(the_repository, notes_ref, &object_oid))
>  		return;
>  	if (flags & NOTES_INIT_WRITABLE && read_ref(notes_ref, &object_oid))
Jeff King· Apr 24, 2023, 21:57 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/2] notes: clean up confusing NULL checks in init_notes()

On Mon, Apr 24, 2023 at 11:05:49AM -0700, Junio C Hamano wrote:
Show 18 quoted lines
> Jeff King <peff@peff.net> writes:
> 
> > Coverity complains that we check whether "notes_ref" is NULL, but it was
> > already implied to be non-NULL earlier in the function. And this is
> > true; since b9342b3fd63 (refs: add array of ref namespaces, 2022-08-05),
> > we call xstrdup(notes_ref) unconditionally, which would segfault if it
> > was NULL.
> >
> > But that commit is actually doing the right thing. Even if NULL is
> > passed into the function, we'll use default_notes_ref() as a fallback,
> > which will never return NULL (it tries a few options, but its last
> > resort is a string literal). Ironically, the "!notes_ref" check was
> > added by the same commit that added the fallback: 709f79b0894 (Notes
> > API: init_notes(): Initialize the notes tree from the given notes ref,
> > 2010-02-13). So this check never did anything.
> 
> I am impressed(?) that Coverity can complain at the "_or_null" part
> in xstrdup_or_null().
No, my human brain added that part while I was looking at the function.

Coverity is definitely clever enough to realize that the NULL check in xstrdup_or_null() is not needed here (it's a static inline, but I think Coverity can even look between translation units). But complaining about it would yield lots of false positives. It's redundant in this instance, but not in other callers of the function.

So it would have to realize: we called xstrdup_or_null(), but there is another function xstrdup() which is exactly the same but without the NULL check. And I think that is asking too much of even a very clever static analyzer. :)

-Peff
Jeff King· Apr 22, 2023, 13:56 UTC · re: Jeff King · lore

[PATCH 2/2] fetch_bundle_uri(): drop pointless NULL check

We check if "uri" is NULL, but it cannot be since we'd have segfaulted earlier in the function when we unconditionally called xstrdup() on it.

In theory we might want to soften that xstrdup() to handle this case, but even before the code which added it via c23f592117 (bundle-uri: fetch a list of bundles, 2022-10-12), we'd have fed NULL to fetch_bundle_uri_internal(), which would also segfault.

The extra check isn't hurting anything, but it does cause Coverity to complain, and it may mislead somebody reading the code into thinking that a NULL uri is something we're prepared to handle.

Signed-off-by: Jeff King <peff@peff.net>
---
 bundle-uri.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
Show changes to bundle-uri.c +2 −2
diff --git a/bundle-uri.c b/bundle-uri.c
index e2b267cc02..f22490a2ca 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -795,10 +795,10 @@ int fetch_bundle_uri(struct repository *r, const char *uri,
 	init_bundle_list(&list);
 
 	/*
-	 * Do not fetch a NULL or empty bundle URI. An empty bundle URI
+	 * Do not fetch an empty bundle URI. An empty bundle URI
 	 * could signal that a configured bundle URI has been disabled.
 	 */
-	if (!uri || !*uri) {
+	if (!*uri) {
 		result = 0;
 		goto cleanup;
 	}
-- 
2.40.0.653.g15ca972062

← back to recent threads