Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | function foo() |
michael@0 | 2 | { |
michael@0 | 3 | // Range analysis incorrectly computes a range for the multiplication. Once |
michael@0 | 4 | // that incorrect range is computed, the goal is to compute a new value whose |
michael@0 | 5 | // range analysis *thinks* is in int32_t range, but which goes past it using |
michael@0 | 6 | // JS semantics. |
michael@0 | 7 | // |
michael@0 | 8 | // On the final iteration, in JS semantics, the multiplication produces 0, and |
michael@0 | 9 | // the next addition 0x7fffffff. Adding any positive integer to that goes |
michael@0 | 10 | // past int32_t range: here, (0x7fffffff + 5) or 2147483652. |
michael@0 | 11 | // |
michael@0 | 12 | // Range analysis instead thinks the multiplication produces a value in the |
michael@0 | 13 | // range [INT32_MIN, INT32_MIN], and the next addition a value in the range |
michael@0 | 14 | // [-1, -1]. Adding any positive value to that doesn't overflow int32_t range |
michael@0 | 15 | // but *does* overflow the actual range in JS semantics. Thus omitting |
michael@0 | 16 | // overflow checks produces the value 0x80000004, which interpreting as signed |
michael@0 | 17 | // is (INT32_MIN + 4) or -2147483644. |
michael@0 | 18 | // |
michael@0 | 19 | // For this test to trigger the bug it was supposed to trigger: |
michael@0 | 20 | // |
michael@0 | 21 | // * 0x7fffffff must be the LHS, not RHS, of the addition in the loop, and |
michael@0 | 22 | // * i must not be incremented using ++ |
michael@0 | 23 | // |
michael@0 | 24 | // The first is required because JM LoopState doesn't treat *both* V + mul and |
michael@0 | 25 | // mul + V as not overflowing, when V is known to be int32_t -- only V + mul. |
michael@0 | 26 | // (JM pessimally assumes V's type might change before it's evaluated. This |
michael@0 | 27 | // obviously can't happen if V is a constant, but JM's puny little mind |
michael@0 | 28 | // doesn't detect this possibility now.) |
michael@0 | 29 | // |
michael@0 | 30 | // The second is required because JM LoopState only ignores integer overflow |
michael@0 | 31 | // on multiplications if the enclosing loop is a "constrainedLoop" (the name |
michael@0 | 32 | // of the relevant field). Loops become unconstrained when unhandled ops are |
michael@0 | 33 | // found in the loop. Increment operators generate a DUP op, which is not |
michael@0 | 34 | // presently a handled op, causing the loop to become unconstrained. |
michael@0 | 35 | for (var i = 0; i < 15; i = i + 1) { |
michael@0 | 36 | var y = (0x7fffffff + ((i & 1) * -2147483648)) + 5; |
michael@0 | 37 | } |
michael@0 | 38 | return y; |
michael@0 | 39 | } |
michael@0 | 40 | assertEq(foo(), (0x7fffffff + ((14 & 1) * -2147483648)) + 5); |
michael@0 | 41 | |
michael@0 | 42 | function bar() |
michael@0 | 43 | { |
michael@0 | 44 | // Variation on the theme of the above test with -1 as the other half of the |
michael@0 | 45 | // INT32_MIN multiplication, which *should* result in -INT32_MIN on multiply |
michael@0 | 46 | // (exceeding int32_t range). |
michael@0 | 47 | // |
michael@0 | 48 | // Here, range analysis again thinks the range of the multiplication is |
michael@0 | 49 | // INT32_MIN. We'd overflow-check except that adding zero (on the LHS, see |
michael@0 | 50 | // above) prevents overflow checking, so range analysis thinks the range is |
michael@0 | 51 | // [INT32_MIN, INT32_MIN] when -INT32_MIN is actually possible. This direct |
michael@0 | 52 | // result of the multiplication is already out of int32_t range, so no need to |
michael@0 | 53 | // add anything to bias it outside int32_t range to get a wrong result. |
michael@0 | 54 | for (var i = 0; i < 17; i = i + 1) { |
michael@0 | 55 | var y = (0 + ((-1 + (i & 1)) * -2147483648)); |
michael@0 | 56 | } |
michael@0 | 57 | return y; |
michael@0 | 58 | } |
michael@0 | 59 | assertEq(bar(), (0 + ((-1 + (16 & 1)) * -2147483648))); |