summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-04-04 11:13:51 +0000
committerDamien George <damien.p.george@gmail.com>2014-04-04 11:13:51 +0000
commitecf5b771230ef747773aa54960ebc2a46902a0ed (patch)
tree904c8ff0678ca81906bb871aa9375954cc2c338c /py
parent6902eeda259a5ed8fe3a5ce5cb19ba9207549d33 (diff)
downloadmicropython-ecf5b771230ef747773aa54960ebc2a46902a0ed.tar.gz
micropython-ecf5b771230ef747773aa54960ebc2a46902a0ed.zip
py: This time, real proper overflow checking of small int power.
Previous overflow test was inadequate.
Diffstat (limited to 'py')
-rw-r--r--py/compile.c6
-rw-r--r--py/intdivmod.c24
-rw-r--r--py/intdivmod.h4
-rw-r--r--py/objint_mpz.c6
-rw-r--r--py/py.mk2
-rw-r--r--py/runtime.c60
-rw-r--r--py/smallint.c53
-rw-r--r--py/smallint.h5
8 files changed, 83 insertions, 77 deletions
diff --git a/py/compile.c b/py/compile.c
index 3273abe40e..44b37b9342 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -17,7 +17,7 @@
#include "obj.h"
#include "compile.h"
#include "runtime.h"
-#include "intdivmod.h"
+#include "smallint.h"
// TODO need to mangle __attr names
@@ -143,10 +143,10 @@ mp_parse_node_t fold_constants(mp_parse_node_t pn) {
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
; // pass
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
- pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_modulo(arg0, arg1));
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
if (arg1 != 0) {
- pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_floor_divide(arg0, arg1));
+ pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
}
} else {
// shouldn't happen
diff --git a/py/intdivmod.c b/py/intdivmod.c
deleted file mode 100644
index 4cb363b511..0000000000
--- a/py/intdivmod.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "mpconfig.h"
-
-machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor) {
- machine_int_t lsign = (dividend >= 0) ? 1 :-1;
- machine_int_t rsign = (divisor >= 0) ? 1 :-1;
- dividend %= divisor;
- if (lsign != rsign) {
- dividend += divisor;
- }
- return dividend;
-}
-
-
-machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom) {
- machine_int_t lsign = num > 0 ? 1 : -1;
- machine_int_t rsign = denom > 0 ? 1 : -1;
- if (lsign == -1) {num *= -1;}
- if (rsign == -1) {denom *= -1;}
- if (lsign != rsign){
- return - ( num + denom - 1) / denom;
- } else {
- return num / denom;
- }
-}
diff --git a/py/intdivmod.h b/py/intdivmod.h
deleted file mode 100644
index 7716bd21e9..0000000000
--- a/py/intdivmod.h
+++ /dev/null
@@ -1,4 +0,0 @@
-// Functions for integer modulo and floor division
-
-machine_int_t python_modulo(machine_int_t dividend, machine_int_t divisor);
-machine_int_t python_floor_divide(machine_int_t num, machine_int_t denom);
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 25a069cf93..d338428135 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -113,7 +113,7 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {
mpz_t rem; mpz_init_zero(&rem);
mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);
- if (zlhs->neg != zrhs->neg) {
+ if (zlhs->neg != zrhs->neg) {
if (!mpz_is_zero(&rem)) {
mpz_t mpzone; mpz_init_from_int(&mpzone, -1);
mpz_add_inpl(&res->mpz, &res->mpz, &mpzone);
@@ -127,8 +127,8 @@ mp_obj_t int_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
mpz_t quo; mpz_init_zero(&quo);
mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);
mpz_deinit(&quo);
- // Check signs and do Python style modulo
- if (zlhs->neg != zrhs->neg) {
+ // Check signs and do Python style modulo
+ if (zlhs->neg != zrhs->neg) {
mpz_add_inpl(&res->mpz, &res->mpz, zrhs);
}
break;
diff --git a/py/py.mk b/py/py.mk
index 059029274e..a08997332b 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -84,7 +84,7 @@ PY_O_BASENAME = \
vm.o \
showbc.o \
repl.o \
- intdivmod.o \
+ smallint.o \
pfenv.o \
# prepend the build destination prefix to the py object files
diff --git a/py/runtime.c b/py/runtime.c
index a5afe0e750..a5f45a2fb4 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -16,7 +16,7 @@
#include "builtin.h"
#include "builtintables.h"
#include "bc.h"
-#include "intdivmod.h"
+#include "smallint.h"
#include "objgenerator.h"
#if 0 // print debugging info
@@ -289,7 +289,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
// If long long type exists and is larger than machine_int_t, then
// we can use the following code to perform overflow-checked multiplication.
- // Otherwise (eg in x64 case) we must use the branching code below.
+ // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow.
#if 0
// compute result using long long precision
long long res = (long long)lhs_val * (long long)rhs_val;
@@ -302,36 +302,14 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
}
#endif
- if (lhs_val > 0) { // lhs_val is positive
- if (rhs_val > 0) { // lhs_val and rhs_val are positive
- if (lhs_val > (MP_SMALL_INT_MAX / rhs_val)) {
- goto mul_overflow;
- }
- } else { // lhs_val positive, rhs_val nonpositive
- if (rhs_val < (MP_SMALL_INT_MIN / lhs_val)) {
- goto mul_overflow;
- }
- } // lhs_val positive, rhs_val nonpositive
- } else { // lhs_val is nonpositive
- if (rhs_val > 0) { // lhs_val is nonpositive, rhs_val is positive
- if (lhs_val < (MP_SMALL_INT_MIN / rhs_val)) {
- goto mul_overflow;
- }
- } else { // lhs_val and rhs_val are nonpositive
- if (lhs_val != 0 && rhs_val < (MP_SMALL_INT_MAX / lhs_val)) {
- goto mul_overflow;
- }
- } // End if lhs_val and rhs_val are nonpositive
- } // End if lhs_val is nonpositive
-
- // use standard precision
- return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
-
- mul_overflow:
- // use higher precision
- lhs = mp_obj_new_int_from_ll(lhs_val);
- goto generic_binary_op;
-
+ if (mp_small_int_mul_overflow(lhs_val, rhs_val)) {
+ // use higher precision
+ lhs = mp_obj_new_int_from_ll(lhs_val);
+ goto generic_binary_op;
+ } else {
+ // use standard precision
+ return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
+ }
break;
}
case MP_BINARY_OP_FLOOR_DIVIDE:
@@ -339,7 +317,7 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
if (rhs_val == 0) {
goto zero_division;
}
- lhs_val = python_floor_divide(lhs_val, rhs_val);
+ lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);
break;
#if MICROPY_ENABLE_FLOAT
@@ -352,11 +330,11 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
#endif
case MP_BINARY_OP_MODULO:
- case MP_BINARY_OP_INPLACE_MODULO:
- {
- lhs_val = python_modulo(lhs_val, rhs_val);
+ case MP_BINARY_OP_INPLACE_MODULO: {
+ lhs_val = mp_small_int_modulo(lhs_val, rhs_val);
break;
}
+
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER:
if (rhs_val < 0) {
@@ -370,21 +348,19 @@ mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
machine_int_t ans = 1;
while (rhs_val > 0) {
if (rhs_val & 1) {
- machine_int_t old = ans;
- ans *= lhs_val;
- if (ans < old) {
+ if (mp_small_int_mul_overflow(ans, lhs_val)) {
goto power_overflow;
}
+ ans *= lhs_val;
}
if (rhs_val == 1) {
break;
}
rhs_val /= 2;
- machine_int_t old = lhs_val;
- lhs_val *= lhs_val;
- if (lhs_val < old) {
+ if (mp_small_int_mul_overflow(lhs_val, lhs_val)) {
goto power_overflow;
}
+ lhs_val *= lhs_val;
}
lhs_val = ans;
}
diff --git a/py/smallint.c b/py/smallint.c
new file mode 100644
index 0000000000..ac0cf2f5f9
--- /dev/null
+++ b/py/smallint.c
@@ -0,0 +1,53 @@
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+
+bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y) {
+ // Check for multiply overflow; see CERT INT32-C
+ if (x > 0) { // x is positive
+ if (y > 0) { // x and y are positive
+ if (x > (MP_SMALL_INT_MAX / y)) {
+ return true;
+ }
+ } else { // x positive, y nonpositive
+ if (y < (MP_SMALL_INT_MIN / x)) {
+ return true;
+ }
+ } // x positive, y nonpositive
+ } else { // x is nonpositive
+ if (y > 0) { // x is nonpositive, y is positive
+ if (x < (MP_SMALL_INT_MIN / y)) {
+ return true;
+ }
+ } else { // x and y are nonpositive
+ if (x != 0 && y < (MP_SMALL_INT_MAX / x)) {
+ return true;
+ }
+ } // End if x and y are nonpositive
+ } // End if x is nonpositive
+ return false;
+}
+
+machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor) {
+ machine_int_t lsign = (dividend >= 0) ? 1 :-1;
+ machine_int_t rsign = (divisor >= 0) ? 1 :-1;
+ dividend %= divisor;
+ if (lsign != rsign) {
+ dividend += divisor;
+ }
+ return dividend;
+}
+
+
+machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom) {
+ machine_int_t lsign = num > 0 ? 1 : -1;
+ machine_int_t rsign = denom > 0 ? 1 : -1;
+ if (lsign == -1) {num *= -1;}
+ if (rsign == -1) {denom *= -1;}
+ if (lsign != rsign){
+ return - ( num + denom - 1) / denom;
+ } else {
+ return num / denom;
+ }
+}
diff --git a/py/smallint.h b/py/smallint.h
new file mode 100644
index 0000000000..14234fa7b8
--- /dev/null
+++ b/py/smallint.h
@@ -0,0 +1,5 @@
+// Functions for small integer arithmetic
+
+bool mp_small_int_mul_overflow(machine_int_t x, machine_int_t y);
+machine_int_t mp_small_int_modulo(machine_int_t dividend, machine_int_t divisor);
+machine_int_t mp_small_int_floor_divide(machine_int_t num, machine_int_t denom);