提交 f63b8c8c 编写于 作者: R Rich Felker

fix off-by-one length failure in strftime/wcsftime and improve error behavior

these functions were spuriously failing in the case where the buffer
size was exactly the number of bytes/characters to be written,
including null termination. since these functions do not have defined
error conditions other than buffer size, a reasonable application may
fail to check the return value when the format string and buffer size
are known to be valid; such an application could then attempt to use a
non-terminated buffer.

in addition to fixing the bug, I have changed the error handling
behavior so that these functions always null-terminate the output
except in the case where the buffer size is zero, and so that they
always write as many characters as possible before failing, rather
than dropping whole fields that do not fit. this actually simplifies
the logic somewhat anyway.
上级 2b1f2f14
...@@ -216,7 +216,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st ...@@ -216,7 +216,7 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
const char *t; const char *t;
int plus; int plus;
unsigned long width; unsigned long width;
for (l=0; l+1<n; f++) { for (l=0; l<n; f++) {
if (!*f) { if (!*f) {
s[l] = 0; s[l] = 0;
return l; return l;
...@@ -230,14 +230,13 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st ...@@ -230,14 +230,13 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
width = strtoul(f, &p, 10); width = strtoul(f, &p, 10);
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1; if (!width && p!=f) width = 1;
if (width >= n-l) return 0;
} else { } else {
width = 0; width = 0;
} }
f = p; f = p;
if (*f == 'E' || *f == 'O') f++; if (*f == 'E' || *f == 'O') f++;
t = __strftime_fmt_1(&buf, &k, *f, tm, loc); t = __strftime_fmt_1(&buf, &k, *f, tm, loc);
if (!t) return 0; if (!t) break;
if (width) { if (width) {
for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--); for (; *t=='+' || *t=='-' || (*t=='0'&&t[1]); t++, k--);
width--; width--;
...@@ -247,14 +246,17 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st ...@@ -247,14 +246,17 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
s[l++] = '-'; s[l++] = '-';
else else
width++; width++;
if (width >= n-l) return 0; for (; width > k && l < n; width--)
for (; width > k; width--)
s[l++] = '0'; s[l++] = '0';
} }
if (k >= n-l) return 0; if (k > n-l) k = n-l;
memcpy(s+l, t, k); memcpy(s+l, t, k);
l += k; l += k;
} }
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0; return 0;
} }
......
...@@ -16,7 +16,7 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co ...@@ -16,7 +16,7 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co
const wchar_t *t; const wchar_t *t;
int plus; int plus;
unsigned long width; unsigned long width;
for (l=0; l+1<n; f++) { for (l=0; l<n; f++) {
if (!*f) { if (!*f) {
s[l] = 0; s[l] = 0;
return l; return l;
...@@ -30,14 +30,13 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co ...@@ -30,14 +30,13 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co
width = wcstoul(f, &p, 10); width = wcstoul(f, &p, 10);
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') { if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1; if (!width && p!=f) width = 1;
if (width >= n-l) return 0;
} else { } else {
width = 0; width = 0;
} }
f = p; f = p;
if (*f == 'E' || *f == 'O') f++; if (*f == 'E' || *f == 'O') f++;
t_mb = __strftime_fmt_1(&buf, &k, *f, tm, loc); t_mb = __strftime_fmt_1(&buf, &k, *f, tm, loc);
if (!t_mb) return 0; if (!t_mb) break;
k = mbstowcs(wbuf, t_mb, sizeof wbuf / sizeof *wbuf); k = mbstowcs(wbuf, t_mb, sizeof wbuf / sizeof *wbuf);
if (k == (size_t)-1) return 0; if (k == (size_t)-1) return 0;
t = wbuf; t = wbuf;
...@@ -50,14 +49,17 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co ...@@ -50,14 +49,17 @@ size_t __wcsftime_l(wchar_t *restrict s, size_t n, const wchar_t *restrict f, co
s[l++] = '-'; s[l++] = '-';
else else
width++; width++;
if (width >= n-l) return 0; for (; width > k && l < n; width--)
for (; width > k; width--)
s[l++] = '0'; s[l++] = '0';
} }
if (k >= n-l) return 0; if (k >= n-l) k = n-l;
wmemcpy(s+l, t, k); wmemcpy(s+l, t, k);
l += k; l += k;
} }
if (n) {
if (l==n) l=n-1;
s[l] = 0;
}
return 0; return 0;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册