summaryrefslogtreecommitdiff
path: root/utf8.c
diff options
context:
space:
mode:
authorschwarze@openbsd.org <schwarze@openbsd.org>2016-05-30 12:57:21 +0000
committerDarren Tucker <dtucker@zip.com.au>2016-06-06 11:27:38 +1000
commitcd9e1eabeb4137182200035ab6fa4522f8d24044 (patch)
treea4428fb623a0698643942b14222740abd5e8f423 /utf8.c
parentac284a355f8065eaef2a16f446f3c44cdd17371d (diff)
downloadopenssh-git-cd9e1eabeb4137182200035ab6fa4522f8d24044.tar.gz
upstream commit
Even when only writing an unescaped character, the dst buffer may need to grow, or it would be overrun; issue found by tb@ with malloc.conf(5) 'C'. While here, reserve an additional byte for the terminating NUL up front such that we don't have to realloc() later just for that. OK tb@ Upstream-ID: 30ebcc0c097c4571b16f0a78b44969f170db0cff
Diffstat (limited to 'utf8.c')
-rw-r--r--utf8.c46
1 files changed, 31 insertions, 15 deletions
diff --git a/utf8.c b/utf8.c
index caf789ce..18ee5385 100644
--- a/utf8.c
+++ b/utf8.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: utf8.c,v 1.2 2016/05/30 12:05:56 schwarze Exp $ */
+/* $OpenBSD: utf8.c,v 1.3 2016/05/30 12:57:21 schwarze Exp $ */
/*
* Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org>
*
@@ -33,6 +33,7 @@
#include "utf8.h"
static int dangerous_locale(void);
+static int grow_dst(char **, size_t *, size_t, char **, size_t);
static int vasnmprintf(char **, size_t, int *, const char *, va_list);
@@ -53,6 +54,25 @@ dangerous_locale(void) {
return strcmp(loc, "US-ASCII") && strcmp(loc, "UTF-8");
}
+static int
+grow_dst(char **dst, size_t *sz, size_t maxsz, char **dp, size_t need)
+{
+ char *tp;
+ size_t tsz;
+
+ if (*dp + need < *dst + *sz)
+ return 0;
+ tsz = *sz + 128;
+ if (tsz > maxsz)
+ tsz = maxsz;
+ if ((tp = realloc(*dst, tsz)) == NULL)
+ return -1;
+ *dp = tp + (*dp - *dst);
+ *dst = tp;
+ *sz = tsz;
+ return 0;
+}
+
/*
* The following two functions limit the number of bytes written,
* including the terminating '\0', to sz. Unless wp is NULL,
@@ -74,7 +94,6 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
char *dp; /* Pointer into dst. */
char *tp; /* Temporary pointer for dst. */
size_t sz; /* Number of bytes allocated for dst. */
- size_t tsz; /* Temporary size while extending dst. */
wchar_t wc; /* Wide character at sp. */
int len; /* Number of bytes in the character at sp. */
int ret; /* Number of bytes needed to format src. */
@@ -85,7 +104,7 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
if ((ret = vasprintf(&src, fmt, ap)) <= 0)
goto fail;
- sz = strlen(src);
+ sz = strlen(src) + 1;
if ((dst = malloc(sz)) == NULL) {
free(src);
goto fail;
@@ -130,6 +149,11 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
total_width > max_width - width))
print = 0;
if (print) {
+ if (grow_dst(&dst, &sz, maxsz,
+ &dp, len) == -1) {
+ ret = -1;
+ break;
+ }
total_width += width;
memcpy(dp, sp, len);
dp += len;
@@ -147,18 +171,10 @@ vasnmprintf(char **str, size_t maxsz, int *wp, const char *fmt, va_list ap)
total_width > max_width - 4))
print = 0;
if (print) {
- if (dp + 4 >= dst + sz) {
- tsz = sz + 128;
- if (tsz > maxsz)
- tsz = maxsz;
- tp = realloc(dst, tsz);
- if (tp == NULL) {
- ret = -1;
- break;
- }
- dp = tp + (dp - dst);
- dst = tp;
- sz = tsz;
+ if (grow_dst(&dst, &sz, maxsz,
+ &dp, 4) == -1) {
+ ret = -1;
+ break;
}
tp = vis(dp, *sp, VIS_OCTAL | VIS_ALL, 0);
width = tp - dp;