From: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, peff@peff.net, newren@gmail.com,
Derrick Stolee <stolee@gmail.com>,
Derrick Stolee <stolee@gmail.com>
Subject: [PATCH 1/6] strbuf: add header for 'safe' API
Date: Fri, 18 Sep 2026 13:02:15 +0000 [thread overview]
Message-ID: <b1779709120adc9c1df40c7210481d6bed9791c5.1789736540.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2230.git.1789736540.gitgitgadget@gmail.com>
From: Derrick Stolee <stolee@gmail.com>
The strbuf library is an important API used all over the Git codebase.
Contributors use it in nearly any string-manipulating action. However, the
implementation uses other helping functions that die() on failure instead of
returning an error code. Thus, the strbuf API isn't _safe_.
In particular, we cannot include 'banned-die.h' in 'strbuf.c'.
To start the creation of a safe strbuf API, move the struct definition into
a new 'strbuf-safe.h' header file. All consumers of 'strbuf.h' will consume
that header transitively.
In the future, we will hope to have consumers that need a 'safe' API will
include 'strbuf-safe.h' instead of 'strbuf.h'.
We will see in future changes the inclusion of new implementations that
return an error code instead of halting.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
strbuf-safe.h | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++
strbuf.h | 74 +++----------------------------------------
2 files changed, 92 insertions(+), 70 deletions(-)
create mode 100644 strbuf-safe.h
diff --git a/strbuf-safe.h b/strbuf-safe.h
new file mode 100644
index 0000000000..3cf14545bb
--- /dev/null
+++ b/strbuf-safe.h
@@ -0,0 +1,88 @@
+#ifndef STRBUF_SAFE_H
+#define STRBUF_SAFE_H
+
+/*
+ * NOTE FOR STRBUF DEVELOPERS
+ *
+ * strbuf is a low-level primitive; as such it should interact only
+ * with other low-level primitives. Do not introduce new functions
+ * which interact with higher-level APIs.
+ *
+ * This header file specifically conatins the "safe" API surface for
+ * working with strbufs. The implementations of these methods avoid
+ * using die() and other exits. Thus, these methods are appropriate
+ * for use within lower-level APIs such as trace2.
+ */
+
+struct string_list;
+
+/**
+ * strbufs are meant to be used with all the usual C string and memory
+ * APIs. Given that the length of the buffer is known, it's often better to
+ * use the mem* functions than a str* one (e.g., memchr vs. strchr).
+ * Though, one has to be careful about the fact that str* functions often
+ * stop on NULs and that strbufs may have embedded NULs.
+ *
+ * A strbuf is NUL terminated for convenience, but no function in the
+ * strbuf API actually relies on the string being free of NULs.
+ *
+ * strbufs have some invariants that are very important to keep in mind:
+ *
+ * - The `buf` member is never NULL, so it can be used in any usual C
+ * string operations safely. strbufs _have_ to be initialized either by
+ * `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
+ *
+ * Do *not* assume anything on what `buf` really is (e.g. if it is
+ * allocated memory or not), use `strbuf_detach()` to unwrap a memory
+ * buffer from its strbuf shell in a safe way. That is the sole supported
+ * way. This will give you a malloced buffer that you can later `free()`.
+ *
+ * However, it is totally safe to modify anything in the string pointed by
+ * the `buf` member, between the indices `0` and `len-1` (inclusive).
+ *
+ * - The `buf` member is a byte array that has at least `len + 1` bytes
+ * allocated. The extra byte is used to store a `'\0'`, allowing the
+ * `buf` member to be a valid C-string. All strbuf functions ensure this
+ * invariant is preserved.
+ *
+ * NOTE: It is OK to "play" with the buffer directly if you work it this
+ * way:
+ *
+ * strbuf_grow(sb, SOME_SIZE); <1>
+ * strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
+ *
+ * <1> Here, the memory array starting at `sb->buf`, and of length
+ * `strbuf_avail(sb)` is all yours, and you can be sure that
+ * `strbuf_avail(sb)` is at least `SOME_SIZE`.
+ *
+ * NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
+ *
+ * Doing so is safe, though if it has to be done in many places, adding the
+ * missing API to the strbuf module is the way to go.
+ *
+ * WARNING: Do _not_ assume that the area that is yours is of size `alloc
+ * - 1` even if it's true in the current implementation. Alloc is somehow a
+ * "private" member that should not be messed with. Use `strbuf_avail()`
+ * instead.
+*/
+
+/**
+ * Data Structures
+ * ---------------
+ */
+
+/**
+ * This is the string buffer structure. The `len` member can be used to
+ * determine the current length of the string, and `buf` member provides
+ * access to the string itself.
+ */
+struct strbuf {
+ size_t alloc;
+ size_t len;
+ char *buf;
+};
+
+extern char strbuf_slopbuf[];
+#define STRBUF_INIT { .buf = strbuf_slopbuf }
+
+#endif /* STRBUF_SAFE_H */
diff --git a/strbuf.h b/strbuf.h
index 1089ae687b..b41f8ef901 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -1,85 +1,19 @@
#ifndef STRBUF_H
#define STRBUF_H
+#include "strbuf-safe.h"
+
/*
* NOTE FOR STRBUF DEVELOPERS
*
* strbuf is a low-level primitive; as such it should interact only
* with other low-level primitives. Do not introduce new functions
* which interact with higher-level APIs.
- */
-
-struct string_list;
-
-/**
- * strbufs are meant to be used with all the usual C string and memory
- * APIs. Given that the length of the buffer is known, it's often better to
- * use the mem* functions than a str* one (e.g., memchr vs. strchr).
- * Though, one has to be careful about the fact that str* functions often
- * stop on NULs and that strbufs may have embedded NULs.
- *
- * A strbuf is NUL terminated for convenience, but no function in the
- * strbuf API actually relies on the string being free of NULs.
- *
- * strbufs have some invariants that are very important to keep in mind:
- *
- * - The `buf` member is never NULL, so it can be used in any usual C
- * string operations safely. strbufs _have_ to be initialized either by
- * `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
- *
- * Do *not* assume anything on what `buf` really is (e.g. if it is
- * allocated memory or not), use `strbuf_detach()` to unwrap a memory
- * buffer from its strbuf shell in a safe way. That is the sole supported
- * way. This will give you a malloced buffer that you can later `free()`.
- *
- * However, it is totally safe to modify anything in the string pointed by
- * the `buf` member, between the indices `0` and `len-1` (inclusive).
- *
- * - The `buf` member is a byte array that has at least `len + 1` bytes
- * allocated. The extra byte is used to store a `'\0'`, allowing the
- * `buf` member to be a valid C-string. All strbuf functions ensure this
- * invariant is preserved.
- *
- * NOTE: It is OK to "play" with the buffer directly if you work it this
- * way:
*
- * strbuf_grow(sb, SOME_SIZE); <1>
- * strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
- *
- * <1> Here, the memory array starting at `sb->buf`, and of length
- * `strbuf_avail(sb)` is all yours, and you can be sure that
- * `strbuf_avail(sb)` is at least `SOME_SIZE`.
- *
- * NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
- *
- * Doing so is safe, though if it has to be done in many places, adding the
- * missing API to the strbuf module is the way to go.
- *
- * WARNING: Do _not_ assume that the area that is yours is of size `alloc
- * - 1` even if it's true in the current implementation. Alloc is somehow a
- * "private" member that should not be messed with. Use `strbuf_avail()`
- * instead.
-*/
-
-/**
- * Data Structures
- * ---------------
+ * Also see strbuf-safe.h for the struct definitions and safe versions
+ * of some methods declared in this header file.
*/
-/**
- * This is the string buffer structure. The `len` member can be used to
- * determine the current length of the string, and `buf` member provides
- * access to the string itself.
- */
-struct strbuf {
- size_t alloc;
- size_t len;
- char *buf;
-};
-
-extern char strbuf_slopbuf[];
-#define STRBUF_INIT { .buf = strbuf_slopbuf }
-
struct object_id;
/**
--
gitgitgadget
next prev parent reply other threads:[~2026-09-18 13:02 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-18 13:02 [PATCH 0/6] [RFC] Create a 'safe' strbuf API Derrick Stolee via GitGitGadget
2026-09-18 13:02 ` Derrick Stolee via GitGitGadget [this message]
2026-09-21 21:18 ` [PATCH 1/6] strbuf: add header for 'safe' API Junio C Hamano
2026-09-23 19:25 ` Mark C. Chu-Carroll
2026-09-23 20:14 ` Junio C Hamano
2026-09-18 13:02 ` [PATCH 2/6] wrapper: initialize GIT_ALLOC_LIMIT proactively Derrick Stolee via GitGitGadget
2026-09-18 13:02 ` [PATCH 3/6] wrapper: create safe_memory_limit_check() Derrick Stolee via GitGitGadget
2026-09-21 21:24 ` Junio C Hamano
2026-09-18 13:02 ` [PATCH 4/6] strbuf-safe: add sstrbuf_grow() Derrick Stolee via GitGitGadget
2026-09-21 21:29 ` Junio C Hamano
2026-09-18 13:02 ` [PATCH 5/6] json-writer: include strbuf-safe.h Derrick Stolee via GitGitGadget
2026-09-18 13:02 ` [PATCH 6/6] strbuf-safe: add init and release methods Derrick Stolee via GitGitGadget
2026-09-21 21:44 ` Junio C Hamano
2026-09-21 22:34 ` Junio C Hamano
2026-09-19 15:23 ` [PATCH 0/6] [RFC] Create a 'safe' strbuf API Phillip Wood
2026-09-23 19:46 ` Jeff King
2026-10-06 14:33 ` Derrick Stolee
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=b1779709120adc9c1df40c7210481d6bed9791c5.1789736540.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=newren@gmail.com \
--cc=peff@peff.net \
--cc=stolee@gmail.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox