Git development
 help / color / mirror / Atom feed
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


  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