diff --git a/stb_sprintf.h b/stb_sprintf.h index e055697..46369d5 100644 --- a/stb_sprintf.h +++ b/stb_sprintf.h @@ -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;