aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-01-07 12:02:47 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-01-07 12:02:47 -0800
commit04b5c9d3d434e1bf6ab0dab42fd27fd4a4dd0721 (patch)
tree01c0223e26b31cfbb3dfb79dbb709dcebac2602d
parentf034e3928783ff7a6491833f358c51cfb082b197 (diff)
properly overflow gep arguments; fixes #1975
-rw-r--r--src/parseTools.js6
-rw-r--r--tests/cases/gepaddoverflow.ll37
-rw-r--r--tests/cases/gepaddoverflow.txt1
3 files changed, 43 insertions, 1 deletions
diff --git a/src/parseTools.js b/src/parseTools.js
index 22e9b94c..cef25ed4 100644
--- a/src/parseTools.js
+++ b/src/parseTools.js
@@ -1640,7 +1640,10 @@ function getFastValue(a, op, b, type) {
}
function getFastValues(list, op, type) {
- assert(op == '+');
+ assert(op === '+' && type === 'i32');
+ for (var i = 0; i < list.length; i++) {
+ if (isNumber(list[i])) list[i] = (list[i]|0) + '';
+ }
var changed = true;
while (changed) {
changed = false;
@@ -1648,6 +1651,7 @@ function getFastValues(list, op, type) {
var fast = getFastValue(list[i], op, list[i+1], type);
var raw = list[i] + op + list[i+1];
if (fast.length < raw.length || fast.indexOf(op) < 0) {
+ if (isNumber(fast)) fast = (fast|0) + '';
list[i] = fast;
list.splice(i+1, 1);
i--;
diff --git a/tests/cases/gepaddoverflow.ll b/tests/cases/gepaddoverflow.ll
new file mode 100644
index 00000000..11246c1d
--- /dev/null
+++ b/tests/cases/gepaddoverflow.ll
@@ -0,0 +1,37 @@
+; ModuleID = 'new.o'
+target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
+target triple = "le32-unknown-nacl"
+
+declare i32 @printf(i8* noalias, ...) nounwind
+
+@x = common global [4194304 x i8] zeroinitializer, align 4
+@.str = private constant [6 x i8] c"*%d*\0A\00", align 1
+
+define i8* @test_gep(i32 %y) nounwind readnone {
+ ; JavaScript uses double precision 64-bit floating point values, with
+ ; a 53 bit mantissa. The maximum precisely representable integer is
+ ; 9007199254740992. A number close to that limit is constructed here
+ ; for the constant part of the getelementptr instruction:
+ ; 4194304 * 2147483647 == 9007199250546688 == 9007199254740992 - 4194304
+ ; If that number appears in JavaScript source instead of being properly
+ ; limited to 32 bits, the %y parameter can be used to exceed the maximum
+ ; precisely representable integer, and make the computation inexact.
+ %test_res = getelementptr [4194304 x i8]* @x, i32 2147483647, i32 %y
+ ret i8* %test_res
+}
+
+define i32 @main() {
+ %res_0 = call i8* (i32)* @test_gep(i32 1000000000)
+ %res_1 = call i8* (i32)* @test_gep(i32 1000000001)
+ %res_0_i = ptrtoint i8* %res_0 to i32
+ %res_1_i = ptrtoint i8* %res_1 to i32
+
+ ; If getelementptr limited the constant part of the offset to 32 bits,
+ ; result will be 1. Otherwise, it cannot be 1 because the large numbers in
+ ; the calculation cannot be accurately represented by floating point math.
+ %res_diff = sub i32 %res_1_i, %res_0_i
+ %printf_res = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0), i32 %res_diff)
+
+ ret i32 0
+}
+
diff --git a/tests/cases/gepaddoverflow.txt b/tests/cases/gepaddoverflow.txt
new file mode 100644
index 00000000..10fd998b
--- /dev/null
+++ b/tests/cases/gepaddoverflow.txt
@@ -0,0 +1 @@
+*1*