From 926f688cd0cc177a779ee3bdb2c6a346383dd8e4 Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 20 May 2010 00:40:51 +0200 Subject: [PATCH] Canonicalize string conversion of nan, inf, -inf. --- src/lib_base.c | 3 +-- src/lib_string.c | 18 ++++++++++++++++-- src/lj_str.c | 32 ++++++++++++++++++++++++-------- src/lj_str.h | 1 + 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/lib_base.c b/src/lib_base.c index 66b514dc..1f677b50 100644 --- a/src/lib_base.c +++ b/src/lib_base.c @@ -413,8 +413,7 @@ LJLIB_CF(print) size = strV(o)->len; } else if (shortcut && tvisnum(o)) { char buf[LUAI_MAXNUMBER2STR]; - lua_Number n = numV(o); - size = (size_t)lua_number2str(buf, n); + size = lj_str_bufnum(buf, o); str = buf; } else { copyTV(L, L->top+1, o); diff --git a/src/lib_string.c b/src/lib_string.c index 1231aeb2..528b3d0e 100644 --- a/src/lib_string.c +++ b/src/lib_string.c @@ -734,9 +734,23 @@ LJLIB_CF(string_format) addintlen(form); sprintf(buff, form, (unsigned LUA_INTFRM_T)lj_lib_checknum(L, arg)); break; - case 'e': case 'E': case 'f': case 'g': case 'G': - sprintf(buff, form, (double)lj_lib_checknum(L, arg)); + case 'e': case 'E': case 'f': case 'g': case 'G': { + TValue tv; + tv.n = lj_lib_checknum(L, arg); + if (LJ_UNLIKELY((tv.u32.hi << 1) >= 0xffe00000)) { + /* Canonicalize output of non-finite values. */ + size_t len = lj_str_bufnum(buff, &tv); + if (strfrmt[-1] == 'E' || strfrmt[-1] == 'G') { + buff[len-3] = buff[len-3] - 0x20; + buff[len-2] = buff[len-2] - 0x20; + buff[len-1] = buff[len-1] - 0x20; + } + luaL_addlstring(&b, buff, len); + continue; + } + sprintf(buff, form, (double)tv.n); break; + } case 'q': addquoted(L, &b, arg); continue; diff --git a/src/lj_str.c b/src/lj_str.c index 7b38cecc..4a9477dd 100644 --- a/src/lj_str.c +++ b/src/lj_str.c @@ -173,13 +173,27 @@ parsedbl: } } +/* Print number to buffer. Canonicalizes non-finite values. */ +size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o) +{ + if (LJ_LIKELY((o->u32.hi << 1) < 0xffe00000)) { /* Finite? */ + lua_Number n = o->n; + return (size_t)lua_number2str(s, n); + } else if (((o->u32.hi & 0x000fffff) | o->u32.lo) != 0) { + s[0] = 'n'; s[1] = 'a'; s[2] = 'n'; return 3; + } else if ((o->u32.hi & 0x80000000) == 0) { + s[0] = 'i'; s[1] = 'n'; s[2] = 'f'; return 3; + } else { + s[0] = '-'; s[1] = 'i'; s[2] = 'n'; s[3] = 'f'; return 4; + } +} + /* Convert number to string. */ GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np) { - char s[LUAI_MAXNUMBER2STR]; - lua_Number n = *np; - size_t len = (size_t)lua_number2str(s, n); - return lj_str_new(L, s, len); + char buf[LUAI_MAXNUMBER2STR]; + size_t len = lj_str_bufnum(buf, (TValue *)np); + return lj_str_new(L, buf, len); } #if LJ_HASJIT @@ -252,10 +266,12 @@ const char *lj_str_pushvf(lua_State *L, const char *fmt, va_list argp) break; } case 'f': { - char buff[LUAI_MAXNUMBER2STR]; - lua_Number n = cast_num(va_arg(argp, LUAI_UACNUMBER)); - MSize len = (MSize)lua_number2str(buff, n); - addstr(L, sb, buff, len); + char buf[LUAI_MAXNUMBER2STR]; + TValue tv; + MSize len; + tv.n = cast_num(va_arg(argp, LUAI_UACNUMBER)); + len = (MSize)lj_str_bufnum(buf, &tv); + addstr(L, sb, buf, len); break; } case 'p': { diff --git a/src/lj_str.h b/src/lj_str.h index cdb04568..50d1ae5f 100644 --- a/src/lj_str.h +++ b/src/lj_str.h @@ -22,6 +22,7 @@ LJ_FUNC void LJ_FASTCALL lj_str_free(global_State *g, GCstr *s); /* Type conversions. */ LJ_FUNC int LJ_FASTCALL lj_str_numconv(const char *s, TValue *n); LJ_FUNC int LJ_FASTCALL lj_str_tonum(GCstr *str, TValue *n); +LJ_FUNC size_t LJ_FASTCALL lj_str_bufnum(char *s, cTValue *o); LJ_FUNCA GCstr * LJ_FASTCALL lj_str_fromnum(lua_State *L, const lua_Number *np); #if LJ_HASJIT LJ_FUNC GCstr * LJ_FASTCALL lj_str_fromint(lua_State *L, int32_t k);