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)
|
||||
{
|
||||
static char hex[] = "0123456789abcdefxp";
|
||||
@ -543,37 +583,9 @@ STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback,
|
||||
s = va_arg(va, char *);
|
||||
if (s == 0)
|
||||
s = (char *)"null";
|
||||
// get the length
|
||||
sn = s;
|
||||
for (;;) {
|
||||
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;
|
||||
// get the length, limited to desired precision
|
||||
// always limit to ~0u chars since our counts are 32b
|
||||
l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u);
|
||||
lead[0] = 0;
|
||||
tail[0] = 0;
|
||||
pr = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user