From: Junio C Hamano <gitster@pobox.com>
To: git@vger.kernel.org
Subject: [RFC] cocci: .buf in a strbuf object can never be NULL
Date: Thu, 19 Mar 2026 15:14:27 -0700 [thread overview]
Message-ID: <xmqqcy0zii0s.fsf@gitster.g> (raw)
In-Reply-To: <xmqq341wnvbk.fsf@gitster.g> (Junio C. Hamano's message of "Thu, 19 Mar 2026 00:15:59 -0700")
Junio C Hamano <gitster@pobox.com> writes:
> Subject: Re: [PATCH] rerere: update to modern representation of empty strbufs
>
> Finally get rid of the special casing that was unnecessary for the
> last 19 years.
>
> Signed-off-by: Junio C Hamano <gitster@pobox.com>
> ---
> rerere.c | 8 ++------
> 1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/rerere.c b/rerere.c
> index 6ec55964e2..0296700f9f 100644
> --- a/rerere.c
> +++ b/rerere.c
> @@ -403,12 +403,8 @@ static int handle_conflict(struct strbuf *out, struct rerere_io *io,
> strbuf_addbuf(out, &two);
> rerere_strbuf_putconflict(out, '>', marker_size);
> if (ctx) {
> - git_hash_update(ctx, one.buf ?
> - one.buf : "",
> - one.len + 1);
> - git_hash_update(ctx, two.buf ?
> - two.buf : "",
> - two.len + 1);
> + git_hash_update(ctx, one.buf, one.len + 1);
> + git_hash_update(ctx, two.buf, two.len + 1);
> }
> break;
> } else if (hunk == RR_SIDE_1)
I wrote a trivial Coccinele rule (attached at the end) to rewrite
SB.buf ? SB.buf : ""
into
SB.buf
and this found only the above instance, which is good.
However, a related rule, "it is nonsense to expect that SB.buf could
sometimes be false", finds two questionable instances.
One is in list-objects-filter-options.c::parse_list_objects_filter()
void parse_list_objects_filter(
struct list_objects_filter_options *filter_options,
const char *arg)
{
struct strbuf errbuf = STRBUF_INIT;
if (!filter_options->filter_spec.buf)
BUG("filter_options not properly initialized");
The filter_options variable points at a list_objects_filter_options
structure, which has an embedded "struct strbuf". This BUG() is
unnecessary if the structure is properly initialized, either by the
LIST_OBJECTS_FILTER_INIT macro or a list_objects_filter_init() call.
But it is easy to memset(&lofo, 0, sizeof(lofo)) or zero initialize
with "= {0}", so I think it is OK to special case and allow for
checking the possibility that .buf might be NULL.
The other exception comes from use of getdelim() in
strbuf_getwholeline(), whose early part reads like this:
int strbuf_getwholeline(struct strbuf *sb, FILE *fp, int term)
{
...
/* Translate slopbuf to NULL, as we cannot call realloc on it */
if (!sb->alloc)
sb->buf = NULL;
errno = 0;
r = getdelim(&sb->buf, &sb->alloc, term, fp);
if (r > 0) {
sb->len = r;
return 0;
}
Before calling getdelim(), we deliberately break the strbuf
invariant ".buf is never NULL; it can point at the slopbuf if .len
is 0". If we read even a single byte, we are OK, as the invariant
is restored.
Upon EOF, later in the function we have
if (!sb->buf)
strbuf_init(sb, 0);
else
strbuf_reset(sb);
return EOF;
to recover the strbuf invariant.
Because strbuf_getwholeline() discards what is originally in sb and
replaces it with what getdelim() returns, I have a suspicion that
working with bare char * and size_t to interact with getdelim() and
then using strbuf_attach() on the success case would be simpler to
read and maintain. Once such a rewrite of this function is done
(#leftoverbits), the special case we see in the Coccinelle rule can
be lifted.
Thoughts?
contrib/coccinelle/strbuf.cocci | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git c/contrib/coccinelle/strbuf.cocci w/contrib/coccinelle/strbuf.cocci
index 5f06105df6..3dc5cd02a3 100644
--- c/contrib/coccinelle/strbuf.cocci
+++ w/contrib/coccinelle/strbuf.cocci
@@ -60,3 +60,18 @@ expression E1, E2;
@@
- strbuf_addstr(E1, real_path(E2));
+ strbuf_add_real_path(E1, E2);
+
+@@
+struct strbuf SB;
+@@
+- SB.buf ? SB.buf : ""
++ SB.buf
+
+@@
+identifier funcname != { strbuf_getwholeline, parse_list_objects_filter };
+struct strbuf SB;
+@@
+ funcname(...) {<...
+- !SB.buf
++ 0
+ ...>}
next prev parent reply other threads:[~2026-03-19 22:14 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-19 7:15 [PATCH] rerere: update to modern representation of empty strbufs Junio C Hamano
2026-03-19 7:57 ` Patrick Steinhardt
2026-03-19 22:14 ` Junio C Hamano [this message]
2026-03-19 23:35 ` [RFC] cocci: .buf in a strbuf object can never be NULL Jeff King
2026-03-20 1:46 ` Junio C Hamano
2026-03-20 4:18 ` Jeff King
2026-03-20 5:45 ` Junio C Hamano
2026-03-20 5:57 ` Jeff King
2026-03-20 6:06 ` Junio C Hamano
2026-03-20 6:18 ` Jeff King
2026-03-21 13:14 ` René Scharfe
2026-03-21 16:41 ` Jeff King
2026-03-21 20:47 ` René Scharfe
2026-03-21 21:18 ` Jeff King
2026-03-21 23:41 ` René Scharfe
2026-03-22 1:44 ` Jeff King
2026-03-22 1:22 ` Junio C Hamano
2026-03-22 1:40 ` Jeff King
2026-03-21 16:24 ` Junio C Hamano
2026-03-21 16:39 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=xmqqcy0zii0s.fsf@gitster.g \
--to=gitster@pobox.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.