[PATCH 4/6] strbuf-safe: add sstrbuf_grow()
From: Derrick Stolee via GitGitGadget <hidden>
Date: 2026-09-18 13:02:30
Subsystem:
kernel build + files below scripts/ (unless maintained elsewhere), the rest · Maintainers:
Nathan Chancellor, Nicolas Schier, Linus Torvalds
From: Derrick Stolee <redacted> After a few changes in preparation, we are now ready to create our first 'safe' strbuf API method: sstrbuf_grow(). This is a safe version of strbuf_grow(). On naming: For safe equivalents of existing methods, I'm prepending a single 's' character. The intention is to make the safe API non-intrusive. Alternatives could be to append '_gentle' like many other APIs that avoid a die() on malformed user data, but we need to be even safer than these gentle methods, which still die() on allocation failures or other system-level errors. This 's' prefix is similar to the 'x' prefix used by git-compat-util helpers. I selected strbuf_grow() as the first method to move because it doesn't depend on any other strbuf API method, but is called by many other strbuf API calls, including strbuf_release() or strbuf_init(). Thus, this will be a helper to several other implementations that are coming in upcoming changes. No callers directly depend on sstrbuf_grow(), but the non-safe strbuf_grow() now uses it as declared in strbuf-safe.h. Signed-off-by: Derrick Stolee <redacted> --- Makefile | 1 + meson.build | 1 + strbuf-safe.c | 34 ++++++++++++++++++++++++++++++++++ strbuf-safe.h | 7 +++++++ strbuf.c | 11 ++++------- wrapper.c | 26 +++++++++++++++++--------- wrapper.h | 3 +++ 7 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 strbuf-safe.c
diff --git a/Makefile b/Makefile
index d4b775953d..5943853219 100644
--- a/Makefile
+++ b/Makefile@@ -1327,6 +1327,7 @@ LIB_OBJS += sparse-index.o LIB_OBJS += split-index.o LIB_OBJS += stable-qsort.o LIB_OBJS += statinfo.o +LIB_OBJS += strbuf-safe.o LIB_OBJS += strbuf.o LIB_OBJS += string-list.o LIB_OBJS += strmap.o
diff --git a/meson.build b/meson.build
index d86f2acd2b..368fdd00d5 100644
--- a/meson.build
+++ b/meson.build@@ -532,6 +532,7 @@ libgit_sources = [ 'split-index.c', 'stable-qsort.c', 'statinfo.c', + 'strbuf-safe.c', 'strbuf.c', 'string-list.c', 'strmap.c',
diff --git a/strbuf-safe.c b/strbuf-safe.c
new file mode 100644
index 0000000000..e4a0707d63
--- /dev/null
+++ b/strbuf-safe.c@@ -0,0 +1,34 @@ +#include "git-compat-util.h" +#include "strbuf-safe.h" +#include "banned-die.h" + +/* + * A safe version of ALLOC_GROW from git-compat-util.h and + * xrealloc() from wrapper.c. + */ +#define SAFE_ALLOC_GROW(x, nr, alloc) \ + do { \ + if ((nr) > alloc) { \ + if (alloc_nr(alloc) < (nr)) \ + alloc = (nr); \ + else \ + alloc = alloc_nr(alloc); \ + if (srealloc((void **)&(x), alloc)) \ + return MEMORY_ERROR; \ + } \ + } while (0) + +enum safe_result sstrbuf_grow(struct strbuf *sb, size_t extra) +{ + int new_buf = !sb->alloc; + size_t new_len = st_add3(sb->len, extra, 1); + if (new_buf) + sb->buf = NULL; + + SAFE_ALLOC_GROW(sb->buf, new_len, sb->alloc); + + if (new_buf) + sb->buf[0] = '\0'; + + return SUCCESS; +}
diff --git a/strbuf-safe.h b/strbuf-safe.h
index 3cf14545bb..f6adf7434b 100644
--- a/strbuf-safe.h
+++ b/strbuf-safe.h@@ -85,4 +85,11 @@ struct strbuf { extern char strbuf_slopbuf[]; #define STRBUF_INIT { .buf = strbuf_slopbuf } +enum safe_result { + SUCCESS = 0, + MEMORY_ERROR, +}; + +enum safe_result sstrbuf_grow(struct strbuf *sb, size_t extra); + #endif /* STRBUF_SAFE_H */
diff --git a/strbuf.c b/strbuf.c
index 44955669e8..d005666a07 100644
--- a/strbuf.c
+++ b/strbuf.c@@ -8,6 +8,8 @@ #include "utf8.h" #include "date.h" +#define STRBUF_DIE(f) die(_("unexpected error during string manipulation: %s"), f) + bool starts_with(const char *str, const char *prefix) { for (; ; str++, prefix++)
@@ -105,13 +107,8 @@ void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc) void strbuf_grow(struct strbuf *sb, size_t extra) { - int new_buf = !sb->alloc; - size_t new_len = st_add3(sb->len, extra, 1); - if (new_buf) - sb->buf = NULL; - ALLOC_GROW(sb->buf, new_len, sb->alloc); - if (new_buf) - sb->buf[0] = '\0'; + if (sstrbuf_grow(sb, extra)) + STRBUF_DIE("strbuf_grow"); } void strbuf_trim(struct strbuf *sb)
diff --git a/wrapper.c b/wrapper.c
index 97a29bda75..69ff9a8ff6 100644
--- a/wrapper.c
+++ b/wrapper.c@@ -144,20 +144,28 @@ int xstrncmpz(const char *s, const char *t, size_t len) return s[len] == '\0' ? 0 : 1; } -void *xrealloc(void *ptr, size_t size) +int srealloc(void **ptr, size_t size) { - void *ret; - if (!size) { - free(ptr); - return xmalloc(0); + free(*ptr); + if ((*ptr = malloc(1))) + return 0; + return -1; } - memory_limit_check(size, 0); - ret = realloc(ptr, size); - if (!ret) + if (safe_memory_limit_check(size, 0)) + return -1; + if ((*ptr = realloc(*ptr, size))) + return 0; + + return -1; +} + +void *xrealloc(void *ptr, size_t size) +{ + if (srealloc(&ptr, size)) die("Out of memory, realloc failed"); - return ret; + return ptr; } void *xcalloc(size_t nmemb, size_t size)
diff --git a/wrapper.h b/wrapper.h
index 69df68ee7a..956de2c534 100644
--- a/wrapper.h
+++ b/wrapper.h@@ -27,6 +27,9 @@ char *xgetcwd(void); FILE *fopen_for_writing(const char *path); FILE *fopen_or_warn(const char *path, const char *mode); +/* safe versions of helpers above. */ +int srealloc(void **ptr, size_t size); + /* * Like strncmp, but only return zero if s is NUL-terminated and exactly len * characters long. If it is not, consider it greater than t.
--
gitgitgadget