[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