diff options
| author | Mike Pall <mike> | 2016-04-21 17:00:58 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2016-04-21 17:00:58 +0200 |
| commit | 2f0001fad05731ea3787b27cf9b19e5293c358b8 (patch) | |
| tree | cbfbb921518399867b24b0d82bf2ccc7fc111bf7 | |
| parent | cc4f5d056ab93521451631f28501015f054d8976 (diff) | |
| download | luajit-2f0001fad05731ea3787b27cf9b19e5293c358b8.tar.gz luajit-2f0001fad05731ea3787b27cf9b19e5293c358b8.tar.bz2 luajit-2f0001fad05731ea3787b27cf9b19e5293c358b8.zip | |
Fix handling of non-numeric strings in arithmetic coercions.
Thanks to Vyacheslav Egorov.
| -rw-r--r-- | src/lj_ffrecord.c | 6 | ||||
| -rw-r--r-- | src/lj_iropt.h | 4 | ||||
| -rw-r--r-- | src/lj_opt_narrow.c | 42 | ||||
| -rw-r--r-- | src/lj_record.c | 4 |
4 files changed, 28 insertions, 28 deletions
diff --git a/src/lj_ffrecord.c b/src/lj_ffrecord.c index c258aee1..99d54233 100644 --- a/src/lj_ffrecord.c +++ b/src/lj_ffrecord.c | |||
| @@ -539,10 +539,8 @@ static void LJ_FASTCALL recff_math_degrad(jit_State *J, RecordFFData *rd) | |||
| 539 | 539 | ||
| 540 | static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) | 540 | static void LJ_FASTCALL recff_math_pow(jit_State *J, RecordFFData *rd) |
| 541 | { | 541 | { |
| 542 | TRef tr = lj_ir_tonum(J, J->base[0]); | 542 | J->base[0] = lj_opt_narrow_pow(J, J->base[0], J->base[1], |
| 543 | if (!tref_isnumber_str(J->base[1])) | 543 | &rd->argv[0], &rd->argv[1]); |
| 544 | lj_trace_err(J, LJ_TRERR_BADTYPE); | ||
| 545 | J->base[0] = lj_opt_narrow_pow(J, tr, J->base[1], &rd->argv[1]); | ||
| 546 | UNUSED(rd); | 544 | UNUSED(rd); |
| 547 | } | 545 | } |
| 548 | 546 | ||
diff --git a/src/lj_iropt.h b/src/lj_iropt.h index 1836e1b0..4bf95f15 100644 --- a/src/lj_iropt.h +++ b/src/lj_iropt.h | |||
| @@ -142,8 +142,8 @@ LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_cindex(jit_State *J, TRef key); | |||
| 142 | LJ_FUNC TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, | 142 | LJ_FUNC TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, |
| 143 | TValue *vb, TValue *vc, IROp op); | 143 | TValue *vb, TValue *vc, IROp op); |
| 144 | LJ_FUNC TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc); | 144 | LJ_FUNC TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc); |
| 145 | LJ_FUNC TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vc); | 145 | LJ_FUNC TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc); |
| 146 | LJ_FUNC TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vc); | 146 | LJ_FUNC TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc); |
| 147 | LJ_FUNC IRType lj_opt_narrow_forl(jit_State *J, cTValue *forbase); | 147 | LJ_FUNC IRType lj_opt_narrow_forl(jit_State *J, cTValue *forbase); |
| 148 | 148 | ||
| 149 | /* Optimization passes. */ | 149 | /* Optimization passes. */ |
diff --git a/src/lj_opt_narrow.c b/src/lj_opt_narrow.c index b1ab5ba8..36be66ee 100644 --- a/src/lj_opt_narrow.c +++ b/src/lj_opt_narrow.c | |||
| @@ -517,18 +517,24 @@ static int numisint(lua_Number n) | |||
| 517 | return (n == (lua_Number)lj_num2int(n)); | 517 | return (n == (lua_Number)lj_num2int(n)); |
| 518 | } | 518 | } |
| 519 | 519 | ||
| 520 | /* Convert string to number. Error out for non-numeric string values. */ | ||
| 521 | static TRef conv_str_tonum(jit_State *J, TRef tr, TValue *o) | ||
| 522 | { | ||
| 523 | if (tref_isstr(tr)) { | ||
| 524 | tr = emitir(IRTG(IR_STRTO, IRT_NUM), tr, 0); | ||
| 525 | /* Would need an inverted STRTO for this rare and useless case. */ | ||
| 526 | if (!lj_strscan_num(strV(o), o)) /* Convert in-place. Value used below. */ | ||
| 527 | lj_trace_err(J, LJ_TRERR_BADTYPE); /* Punt if non-numeric. */ | ||
| 528 | } | ||
| 529 | return tr; | ||
| 530 | } | ||
| 531 | |||
| 520 | /* Narrowing of arithmetic operations. */ | 532 | /* Narrowing of arithmetic operations. */ |
| 521 | TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, | 533 | TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, |
| 522 | TValue *vb, TValue *vc, IROp op) | 534 | TValue *vb, TValue *vc, IROp op) |
| 523 | { | 535 | { |
| 524 | if (tref_isstr(rb)) { | 536 | rb = conv_str_tonum(J, rb, vb); |
| 525 | rb = emitir(IRTG(IR_STRTO, IRT_NUM), rb, 0); | 537 | rc = conv_str_tonum(J, rc, vc); |
| 526 | lj_strscan_num(strV(vb), vb); | ||
| 527 | } | ||
| 528 | if (tref_isstr(rc)) { | ||
| 529 | rc = emitir(IRTG(IR_STRTO, IRT_NUM), rc, 0); | ||
| 530 | lj_strscan_num(strV(vc), vc); | ||
| 531 | } | ||
| 532 | /* Must not narrow MUL in non-DUALNUM variant, because it loses -0. */ | 538 | /* Must not narrow MUL in non-DUALNUM variant, because it loses -0. */ |
| 533 | if ((op >= IR_ADD && op <= (LJ_DUALNUM ? IR_MUL : IR_SUB)) && | 539 | if ((op >= IR_ADD && op <= (LJ_DUALNUM ? IR_MUL : IR_SUB)) && |
| 534 | tref_isinteger(rb) && tref_isinteger(rc) && | 540 | tref_isinteger(rb) && tref_isinteger(rc) && |
| @@ -543,10 +549,7 @@ TRef lj_opt_narrow_arith(jit_State *J, TRef rb, TRef rc, | |||
| 543 | /* Narrowing of unary minus operator. */ | 549 | /* Narrowing of unary minus operator. */ |
| 544 | TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) | 550 | TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) |
| 545 | { | 551 | { |
| 546 | if (tref_isstr(rc)) { | 552 | rc = conv_str_tonum(J, rc, vc); |
| 547 | rc = emitir(IRTG(IR_STRTO, IRT_NUM), rc, 0); | ||
| 548 | lj_strscan_num(strV(vc), vc); | ||
| 549 | } | ||
| 550 | if (tref_isinteger(rc)) { | 553 | if (tref_isinteger(rc)) { |
| 551 | if ((uint32_t)numberVint(vc) != 0x80000000u) | 554 | if ((uint32_t)numberVint(vc) != 0x80000000u) |
| 552 | return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); | 555 | return emitir(IRTGI(IR_SUBOV), lj_ir_kint(J, 0), rc); |
| @@ -556,11 +559,11 @@ TRef lj_opt_narrow_unm(jit_State *J, TRef rc, TValue *vc) | |||
| 556 | } | 559 | } |
| 557 | 560 | ||
| 558 | /* Narrowing of modulo operator. */ | 561 | /* Narrowing of modulo operator. */ |
| 559 | TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vc) | 562 | TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc) |
| 560 | { | 563 | { |
| 561 | TRef tmp; | 564 | TRef tmp; |
| 562 | if (tvisstr(vc) && !lj_strscan_num(strV(vc), vc)) | 565 | rb = conv_str_tonum(J, rb, vb); |
| 563 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 566 | rc = conv_str_tonum(J, rc, vc); |
| 564 | if ((LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) && | 567 | if ((LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) && |
| 565 | tref_isinteger(rb) && tref_isinteger(rc) && | 568 | tref_isinteger(rb) && tref_isinteger(rc) && |
| 566 | (tvisint(vc) ? intV(vc) != 0 : !tviszero(vc))) { | 569 | (tvisint(vc) ? intV(vc) != 0 : !tviszero(vc))) { |
| @@ -577,10 +580,11 @@ TRef lj_opt_narrow_mod(jit_State *J, TRef rb, TRef rc, TValue *vc) | |||
| 577 | } | 580 | } |
| 578 | 581 | ||
| 579 | /* Narrowing of power operator or math.pow. */ | 582 | /* Narrowing of power operator or math.pow. */ |
| 580 | TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vc) | 583 | TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vb, TValue *vc) |
| 581 | { | 584 | { |
| 582 | if (tvisstr(vc) && !lj_strscan_num(strV(vc), vc)) | 585 | rb = conv_str_tonum(J, rb, vb); |
| 583 | lj_trace_err(J, LJ_TRERR_BADTYPE); | 586 | rb = lj_ir_tonum(J, rb); /* Left arg is always treated as an FP number. */ |
| 587 | rc = conv_str_tonum(J, rc, vc); | ||
| 584 | /* Narrowing must be unconditional to preserve (-x)^i semantics. */ | 588 | /* Narrowing must be unconditional to preserve (-x)^i semantics. */ |
| 585 | if (tvisint(vc) || numisint(numV(vc))) { | 589 | if (tvisint(vc) || numisint(numV(vc))) { |
| 586 | int checkrange = 0; | 590 | int checkrange = 0; |
| @@ -591,8 +595,6 @@ TRef lj_opt_narrow_pow(jit_State *J, TRef rb, TRef rc, TValue *vc) | |||
| 591 | checkrange = 1; | 595 | checkrange = 1; |
| 592 | } | 596 | } |
| 593 | if (!tref_isinteger(rc)) { | 597 | if (!tref_isinteger(rc)) { |
| 594 | if (tref_isstr(rc)) | ||
| 595 | rc = emitir(IRTG(IR_STRTO, IRT_NUM), rc, 0); | ||
| 596 | /* Guarded conversion to integer! */ | 598 | /* Guarded conversion to integer! */ |
| 597 | rc = emitir(IRTGI(IR_CONV), rc, IRCONV_INT_NUM|IRCONV_CHECK); | 599 | rc = emitir(IRTGI(IR_CONV), rc, IRCONV_INT_NUM|IRCONV_CHECK); |
| 598 | } | 600 | } |
diff --git a/src/lj_record.c b/src/lj_record.c index 9b51c51f..ff7825ee 100644 --- a/src/lj_record.c +++ b/src/lj_record.c | |||
| @@ -1884,14 +1884,14 @@ void lj_record_ins(jit_State *J) | |||
| 1884 | case BC_MODVN: case BC_MODVV: | 1884 | case BC_MODVN: case BC_MODVV: |
| 1885 | recmod: | 1885 | recmod: |
| 1886 | if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) | 1886 | if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) |
| 1887 | rc = lj_opt_narrow_mod(J, rb, rc, rcv); | 1887 | rc = lj_opt_narrow_mod(J, rb, rc, rbv, rcv); |
| 1888 | else | 1888 | else |
| 1889 | rc = rec_mm_arith(J, &ix, MM_mod); | 1889 | rc = rec_mm_arith(J, &ix, MM_mod); |
| 1890 | break; | 1890 | break; |
| 1891 | 1891 | ||
| 1892 | case BC_POW: | 1892 | case BC_POW: |
| 1893 | if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) | 1893 | if (tref_isnumber_str(rb) && tref_isnumber_str(rc)) |
| 1894 | rc = lj_opt_narrow_pow(J, lj_ir_tonum(J, rb), rc, rcv); | 1894 | rc = lj_opt_narrow_pow(J, rb, rc, rbv, rcv); |
| 1895 | else | 1895 | else |
| 1896 | rc = rec_mm_arith(J, &ix, MM_pow); | 1896 | rc = rec_mm_arith(J, &ix, MM_pow); |
| 1897 | break; | 1897 | break; |
