diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-28 15:03:48 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-12-28 15:03:48 -0300 |
commit | 2a307f898be2716638e7ac30d119f7cd9bbbe096 (patch) | |
tree | 42e65bdf82555d01fb7610de6910ca742aad3660 | |
parent | f81d0bbd4f940399eb4b68845802bc3fe1cad73a (diff) | |
download | lua-2a307f898be2716638e7ac30d119f7cd9bbbe096.tar.gz lua-2a307f898be2716638e7ac30d119f7cd9bbbe096.tar.bz2 lua-2a307f898be2716638e7ac30d119f7cd9bbbe096.zip |
When parser reuses constants, only floats can collide
Ensure that float constants never use integer keys, so that only
floats can collide in 'k2proto'.
-rw-r--r-- | lcode.c | 54 |
1 files changed, 28 insertions, 26 deletions
@@ -557,8 +557,6 @@ static int addk (FuncState *fs, Proto *f, TValue *v) { | |||
557 | ** and try to reuse constants. Because some values should not be used | 557 | ** and try to reuse constants. Because some values should not be used |
558 | ** as keys (nil cannot be a key, integer keys can collapse with float | 558 | ** as keys (nil cannot be a key, integer keys can collapse with float |
559 | ** keys), the caller must provide a useful 'key' for indexing the cache. | 559 | ** keys), the caller must provide a useful 'key' for indexing the cache. |
560 | ** Note that all functions share the same table, so entering or exiting | ||
561 | ** a function can make some indices wrong. | ||
562 | */ | 560 | */ |
563 | static int k2proto (FuncState *fs, TValue *key, TValue *v) { | 561 | static int k2proto (FuncState *fs, TValue *key, TValue *v) { |
564 | TValue val; | 562 | TValue val; |
@@ -567,15 +565,14 @@ static int k2proto (FuncState *fs, TValue *key, TValue *v) { | |||
567 | int k; | 565 | int k; |
568 | if (!tagisempty(tag)) { /* is there an index there? */ | 566 | if (!tagisempty(tag)) { /* is there an index there? */ |
569 | k = cast_int(ivalue(&val)); | 567 | k = cast_int(ivalue(&val)); |
570 | lua_assert(k < fs->nk); | 568 | /* collisions can happen only for float keys */ |
571 | /* correct value? (warning: must distinguish floats from integers!) */ | 569 | lua_assert(ttisfloat(key) || luaV_rawequalobj(&f->k[k], v)); |
572 | if (ttypetag(&f->k[k]) == ttypetag(v) && luaV_rawequalobj(&f->k[k], v)) | 570 | return k; /* reuse index */ |
573 | return k; /* reuse index */ | ||
574 | } | 571 | } |
575 | /* constant not found; create a new entry */ | 572 | /* constant not found; create a new entry */ |
576 | k = addk(fs, f, v); | 573 | k = addk(fs, f, v); |
577 | /* cache for reuse; numerical value does not need GC barrier; | 574 | /* cache it for reuse; numerical value does not need GC barrier; |
578 | table has no metatable, so it does not need to invalidate cache */ | 575 | table is not a metatable, so it does not need to invalidate cache */ |
579 | setivalue(&val, k); | 576 | setivalue(&val, k); |
580 | luaH_set(fs->ls->L, fs->kcache, key, &val); | 577 | luaH_set(fs->ls->L, fs->kcache, key, &val); |
581 | return k; | 578 | return k; |
@@ -607,27 +604,32 @@ static int luaK_intK (FuncState *fs, lua_Integer n) { | |||
607 | ** with actual integers. To that, we add to the number its smaller | 604 | ** with actual integers. To that, we add to the number its smaller |
608 | ** power-of-two fraction that is still significant in its scale. | 605 | ** power-of-two fraction that is still significant in its scale. |
609 | ** For doubles, that would be 1/2^52. | 606 | ** For doubles, that would be 1/2^52. |
610 | ** (This method is not bulletproof: there may be another float | 607 | ** This method is not bulletproof: different numbers may generate the |
611 | ** with that value, and for floats larger than 2^53 the result is | 608 | ** same key (e.g., very large numbers will overflow to 'inf') and for |
612 | ** still an integer. At worst, this only wastes an entry with | 609 | ** floats larger than 2^53 the result is still an integer. At worst, |
613 | ** a duplicate.) | 610 | ** this only wastes an entry with a duplicate. |
614 | */ | 611 | */ |
615 | static int luaK_numberK (FuncState *fs, lua_Number r) { | 612 | static int luaK_numberK (FuncState *fs, lua_Number r) { |
616 | TValue o; | 613 | TValue o, kv; |
617 | lua_Integer ik; | 614 | setfltvalue(&o, r); /* value as a TValue */ |
618 | setfltvalue(&o, r); | 615 | if (r == 0) { /* handle zero as a special case */ |
619 | if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ | 616 | setpvalue(&kv, fs); /* use FuncState as index */ |
620 | return k2proto(fs, &o, &o); /* use number itself as key */ | 617 | return k2proto(fs, &kv, &o); /* cannot collide */ |
621 | else { /* must build an alternative key */ | 618 | } |
619 | else { | ||
622 | const int nbm = l_floatatt(MANT_DIG); | 620 | const int nbm = l_floatatt(MANT_DIG); |
623 | const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); | 621 | const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); |
624 | const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ | 622 | const lua_Number k = r * (1 + q); /* key */ |
625 | TValue kv; | 623 | lua_Integer ik; |
626 | setfltvalue(&kv, k); | 624 | setfltvalue(&kv, k); /* key as a TValue */ |
627 | /* result is not an integral value, unless value is too large */ | 625 | if (!luaV_flttointeger(k, &ik, F2Ieq)) { /* not an integral value? */ |
628 | lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || | 626 | int n = k2proto(fs, &kv, &o); /* use key */ |
629 | l_mathop(fabs)(r) >= l_mathop(1e6)); | 627 | if (luaV_rawequalobj(&fs->f->k[n], &o)) /* correct value? */ |
630 | return k2proto(fs, &kv, &o); | 628 | return n; |
629 | } | ||
630 | /* else, either key is still an integer or there was a collision; | ||
631 | anyway, do not try to reuse constant; instead, create a new one */ | ||
632 | return addk(fs, fs->f, &o); | ||
631 | } | 633 | } |
632 | } | 634 | } |
633 | 635 | ||
@@ -658,7 +660,7 @@ static int boolT (FuncState *fs) { | |||
658 | static int nilK (FuncState *fs) { | 660 | static int nilK (FuncState *fs) { |
659 | TValue k, v; | 661 | TValue k, v; |
660 | setnilvalue(&v); | 662 | setnilvalue(&v); |
661 | /* cannot use nil as key; instead use table itself to represent nil */ | 663 | /* cannot use nil as key; instead use table itself */ |
662 | sethvalue(fs->ls->L, &k, fs->kcache); | 664 | sethvalue(fs->ls->L, &k, fs->kcache); |
663 | return k2proto(fs, &k, &v); | 665 | return k2proto(fs, &k, &v); |
664 | } | 666 | } |