utf8: refactor strbuf_utf8_replace to not rely on preallocated buffer

In `strbuf_utf8_replace`, we preallocate the destination buffer and then
use `memcpy` to copy bytes into it at computed offsets. This feels
rather fragile and is hard to understand at times. Refactor the code to
instead use `strbuf_add` and `strbuf_addstr` so that we can be sure that
there is no possibility to perform an out-of-bounds write.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt 2022-12-01 15:47:15 +01:00 committed by Junio C Hamano
parent 81c2d4c3a5
commit f930a23943

34
utf8.c
View File

@ -365,26 +365,20 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width, void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
const char *subst) const char *subst)
{ {
struct strbuf sb_dst = STRBUF_INIT; const char *src = sb_src->buf, *end = sb_src->buf + sb_src->len;
char *src = sb_src->buf; struct strbuf dst;
char *end = src + sb_src->len; int w = 0;
char *dst;
int w = 0, subst_len = 0;
if (subst) strbuf_init(&dst, sb_src->len);
subst_len = strlen(subst);
strbuf_grow(&sb_dst, sb_src->len + subst_len);
dst = sb_dst.buf;
while (src < end) { while (src < end) {
const char *old;
int glyph_width; int glyph_width;
char *old;
size_t n; size_t n;
while ((n = display_mode_esc_sequence_len(src))) { while ((n = display_mode_esc_sequence_len(src))) {
memcpy(dst, src, n); strbuf_add(&dst, src, n);
src += n; src += n;
dst += n;
} }
if (src >= end) if (src >= end)
@ -404,21 +398,19 @@ void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
if (glyph_width && w >= pos && w < pos + width) { if (glyph_width && w >= pos && w < pos + width) {
if (subst) { if (subst) {
memcpy(dst, subst, subst_len); strbuf_addstr(&dst, subst);
dst += subst_len;
subst = NULL; subst = NULL;
} }
w += glyph_width; } else {
continue; strbuf_add(&dst, old, src - old);
} }
memcpy(dst, old, src - old);
dst += src - old;
w += glyph_width; w += glyph_width;
} }
strbuf_setlen(&sb_dst, dst - sb_dst.buf);
strbuf_swap(sb_src, &sb_dst); strbuf_swap(sb_src, &dst);
out: out:
strbuf_release(&sb_dst); strbuf_release(&dst);
} }
/* /*