stb_sprintf: Fix string length calc
Factor out string length computation into helper func, comment it a bit more, always use a limit to avoid 32b unsigned overflow, and avoid reading past the bounds of non-0-terminated strings given with specified precision. Fixes issue #966.
This commit is contained in:
parent
2af2e69219
commit
013884b53b
@ -300,6 +300,46 @@ static void stbsp__lead_sign(stbsp__uint32 fl, char *sign)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit)
|
||||||
|
{
|
||||||
|
char const * sn = s;
|
||||||
|
|
||||||
|
// get up to 4-byte alignment
|
||||||
|
for (;;) {
|
||||||
|
if (((stbsp__uintptr)sn & 3) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!limit || *sn == 0)
|
||||||
|
return (stbsp__uint32)(sn - s);
|
||||||
|
|
||||||
|
++sn;
|
||||||
|
--limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan over 4 bytes at a time to find terminating 0
|
||||||
|
// this will intentionally scan up to 3 bytes past the end of buffers,
|
||||||
|
// but becase it works 4B aligned, it will never cross page boundaries
|
||||||
|
// (hence the STBSP__ASAN markup; the over-read here is intentional
|
||||||
|
// and harmless)
|
||||||
|
while (limit >= 4) {
|
||||||
|
stbsp__uint32 v = *(stbsp__uint32 *)sn;
|
||||||
|
// bit hack to find if there's a 0 byte in there
|
||||||
|
if ((v - 0x01010101) & (~v) & 0x80808080UL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
sn += 4;
|
||||||
|
limit -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the last few characters to find actual size
|
||||||
|
while (limit && *sn) {
|
||||||
|
++sn;
|
||||||
|
--limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (stbsp__uint32)(sn - s);
|
||||||
|
}
|
||||||
|
|
||||||
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
|
STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va)
|
||||||
{
|
{
|
||||||
static char hex[] = "0123456789abcdefxp";
|
static char hex[] = "0123456789abcdefxp";
|
||||||
@ -543,37 +583,9 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
|
|||||||
s = va_arg(va, char *);
|
s = va_arg(va, char *);
|
||||||
if (s == 0)
|
if (s == 0)
|
||||||
s = (char *)"null";
|
s = (char *)"null";
|
||||||
// get the length
|
// get the length, limited to desired precision
|
||||||
sn = s;
|
// always limit to ~0u chars since our counts are 32b
|
||||||
for (;;) {
|
l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u);
|
||||||
if ((((stbsp__uintptr)sn) & 3) == 0)
|
|
||||||
break;
|
|
||||||
lchk:
|
|
||||||
if (sn[0] == 0)
|
|
||||||
goto ld;
|
|
||||||
++sn;
|
|
||||||
}
|
|
||||||
n = 0xffffffff;
|
|
||||||
if (pr >= 0) {
|
|
||||||
n = (stbsp__uint32)(sn - s);
|
|
||||||
if (n >= (stbsp__uint32)pr)
|
|
||||||
goto ld;
|
|
||||||
n = ((stbsp__uint32)(pr - n)) >> 2;
|
|
||||||
}
|
|
||||||
while (n) {
|
|
||||||
stbsp__uint32 v = *(stbsp__uint32 *)sn;
|
|
||||||
if ((v - 0x01010101) & (~v) & 0x80808080UL)
|
|
||||||
goto lchk;
|
|
||||||
sn += 4;
|
|
||||||
--n;
|
|
||||||
}
|
|
||||||
goto lchk;
|
|
||||||
ld:
|
|
||||||
|
|
||||||
l = (stbsp__uint32)(sn - s);
|
|
||||||
// clamp to precision
|
|
||||||
if (l > (stbsp__uint32)pr)
|
|
||||||
l = pr;
|
|
||||||
lead[0] = 0;
|
lead[0] = 0;
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
pr = 0;
|
pr = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user