git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 6/6] strbuf-safe: add init and release methods

From
Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Date
Sep 18, 2026, 13:02 UTC
Message-ID
<dea925f31647e7c08f3fa467b8058351b463f593.1789736540.git.gitgitgadget@gmail.com>
In-Reply-To
<pull.2230.git.1789736540.gitgitgadget@gmail.com>
From: Derrick Stolee <stolee@gmail.com>

Continue extending the strbuf-safe API by adding these safe versions of the initialize and release methods:

* sstrbuf_init()
* sstrbuf_release()

These both depend on sstrbuf_grow() that was introduced in the previous change.

As we are working to make json-writer.c a safe API, adapt its use of strbuf_release() to the safe version. To properly handle the responses of the safe versions, some methods are converted to return their own error codes. However, callers of those methods are not adapted at this time and will be adapted in future changes. This leaves a window where json-writer consumers may continue running after an error occurs, potentially leading to a different error in the future.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
 json-writer.c | 31 +++++++++++++++++++------------
 json-writer.h |  5 +++--
 strbuf-safe.c | 18 ++++++++++++++++++
 strbuf-safe.h |  2 ++
 strbuf.c      | 12 ++++--------
 5 files changed, 46 insertions(+), 22 deletions(-)
diff --git a/json-writer.c b/json-writer.c
index e7fc5775da..38351f3439 100644
--- a/json-writer.c
+++ b/json-writer.c
@@ -3,6 +3,8 @@
 #include "git-compat-util.h"
 #include "json-writer.h"
 #include "strbuf.h"
+/* banned-die must be last. */
+#include "banned-die.h"
 
 void jw_init(struct json_writer *jw)
 {
@@ -10,10 +12,15 @@ void jw_init(struct json_writer *jw)
 	memcpy(jw, &blank, sizeof(*jw));;
 }
 
-void jw_release(struct json_writer *jw)
+int jw_release(struct json_writer *jw)
 {
-	strbuf_release(&jw->json);
-	strbuf_release(&jw->open_stack);
+	enum safe_result result = SUCCESS;
+
+	/* attempt both removals without short-circuiting. */
+	result = sstrbuf_release(&jw->json) || result;
+	result = sstrbuf_release(&jw->open_stack) || result;
+
+	return result;
 }
 
 /*
@@ -99,16 +106,17 @@ static void maybe_add_comma(struct json_writer *jw)
 		jw->need_comma = 1;
 }
 
-static void fmt_double(struct json_writer *jw, int precision,
-			      double value)
+static int fmt_double(struct json_writer *jw, int precision,
+		      double value)
 {
 	if (precision < 0) {
 		strbuf_addf(&jw->json, "%f", value);
+		return 0;
 	} else {
 		struct strbuf fmt = STRBUF_INIT;
 		strbuf_addf(&fmt, "%%.%df", precision);
 		strbuf_addf(&jw->json, fmt.buf, value);
-		strbuf_release(&fmt);
+		return sstrbuf_release(&fmt);
 	}
 }
 
@@ -235,8 +243,8 @@ static void kill_indent(struct strbuf *sb,
 	}
 }
 
-static void append_sub_jw(struct json_writer *jw,
-			  const struct json_writer *value)
+static int append_sub_jw(struct json_writer *jw,
+			 const struct json_writer *value)
 {
 	/*
 	 * If both are pretty, increase the indentation of the sub_jw
@@ -255,18 +263,17 @@ static void append_sub_jw(struct json_writer *jw,
 		struct strbuf sb = STRBUF_INIT;
 		increase_indent(&sb, value, jw->open_stack.len * 2);
 		strbuf_addbuf(&jw->json, &sb);
-		strbuf_release(&sb);
-		return;
+		return sstrbuf_release(&sb);
 	}
 	if (!jw->pretty && value->pretty) {
 		struct strbuf sb = STRBUF_INIT;
 		kill_indent(&sb, value);
 		strbuf_addbuf(&jw->json, &sb);
-		strbuf_release(&sb);
-		return;
+		return sstrbuf_release(&sb);
 	}
 
 	strbuf_addbuf(&jw->json, &value->json);
+	return 0;
 }
 
 void jw_object_sub_jw(struct json_writer *jw, const char *key,
diff --git a/json-writer.h b/json-writer.h
index fa8cf02253..72277d9839 100644
--- a/json-writer.h
+++ b/json-writer.h
@@ -103,9 +103,10 @@ struct json_writer
 void jw_init(struct json_writer *jw);
 
 /*
- * Release the internal buffers of a json_writer.
+ * Release the internal buffers of a json_writer. Returns nonzero on
+ * failure.
  */
-void jw_release(struct json_writer *jw);
+int jw_release(struct json_writer *jw);
 
 /*
  * Begin the json_writer using an object as the top-level data structure. If
diff --git a/strbuf-safe.c b/strbuf-safe.c
index e4a0707d63..7a8701e827 100644
--- a/strbuf-safe.c
+++ b/strbuf-safe.c
@@ -32,3 +32,21 @@ enum safe_result sstrbuf_grow(struct strbuf *sb, size_t extra)
 
 	return SUCCESS;
 }
+
+enum safe_result sstrbuf_init(struct strbuf *sb, size_t hint)
+{
+	struct strbuf blank = STRBUF_INIT;
+	memcpy(sb, &blank, sizeof(*sb));
+	if (!hint)
+		return 0;
+	return sstrbuf_grow(sb, hint);
+}
+
+enum safe_result sstrbuf_release(struct strbuf *sb)
+{
+	if (sb->alloc) {
+		free(sb->buf);
+		return sstrbuf_init(sb, 0);
+	}
+	return 0;
+}
diff --git a/strbuf-safe.h b/strbuf-safe.h
index f6adf7434b..fe04d9cf62 100644
--- a/strbuf-safe.h
+++ b/strbuf-safe.h
@@ -91,5 +91,7 @@ enum safe_result {
 };
 
 enum safe_result sstrbuf_grow(struct strbuf *sb, size_t extra);
+enum safe_result sstrbuf_init(struct strbuf *sb, size_t hint);
+enum safe_result sstrbuf_release(struct strbuf *sb);
 
 #endif /* STRBUF_SAFE_H */
diff --git a/strbuf.c b/strbuf.c
index d005666a07..835238dc64 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -70,18 +70,14 @@ char strbuf_slopbuf[1];
 
 void strbuf_init(struct strbuf *sb, size_t hint)
 {
-	struct strbuf blank = STRBUF_INIT;
-	memcpy(sb, &blank, sizeof(*sb));
-	if (hint)
-		strbuf_grow(sb, hint);
+	if (sstrbuf_init(sb, hint))
+		STRBUF_DIE("strbuf_init");
 }
 
 void strbuf_release(struct strbuf *sb)
 {
-	if (sb->alloc) {
-		free(sb->buf);
-		strbuf_init(sb, 0);
-	}
+	if (sstrbuf_release(sb))
+		STRBUF_DIE("strbuf_release");
 }
 
 char *strbuf_detach(struct strbuf *sb, size_t *sz)
-- 
gitgitgadget
Previous: Derrick Stolee via GitGitGadgetNext: Junio C Hamano
Message 12 of 17 in “[RFC] Create a 'safe' strbuf API”
  1. 0/6 [RFC] Create a 'safe' strbuf APIDerrick Stolee via GitGitGadget, Sep 18, 2026
  2. 1/6 strbuf: add header for 'safe' APIDerrick Stolee via GitGitGadget, Sep 18, 2026
  3. Junio C HamanoSep 21, 2026
  4. Mark C. Chu-CarrollSep 23, 2026
  5. Junio C HamanoSep 23, 2026
  6. 2/6 wrapper: initialize GIT_ALLOC_LIMIT proactivelyDerrick Stolee via GitGitGadget, Sep 18, 2026
  7. 3/6 wrapper: create safe_memory_limit_check()Derrick Stolee via GitGitGadget, Sep 18, 2026
  8. Junio C HamanoSep 21, 2026
  9. 4/6 strbuf-safe: add sstrbuf_grow()Derrick Stolee via GitGitGadget, Sep 18, 2026
  10. Junio C HamanoSep 21, 2026
  11. 5/6 json-writer: include strbuf-safe.hDerrick Stolee via GitGitGadget, Sep 18, 2026
  12. 6/6 strbuf-safe: add init and release methodsDerrick Stolee via GitGitGadget, Sep 18, 2026
  13. Junio C HamanoSep 21, 2026
  14. Junio C HamanoSep 21, 2026
  15. Phillip WoodSep 19, 2026
  16. Jeff KingSep 23, 2026
  17. Derrick StoleeOct 6, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.