Skip to content

Commit e5635f4

Browse files
committed
py: Catch all cases of integer (big and small) division by zero.
1 parent 2065373 commit e5635f4

File tree

7 files changed

+45
-1
lines changed

7 files changed

+45
-1
lines changed

py/compile.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,9 @@ STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_m
293293
// pass
294294
} else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
295295
// int%int
296-
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
296+
if (arg1 != 0) {
297+
pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
298+
}
297299
} else {
298300
assert(MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)); // should be
299301
if (arg1 != 0) {

py/objint_mpz.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
193193
if (0) {
194194
#if MICROPY_PY_BUILTINS_FLOAT
195195
} else if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) {
196+
if (mpz_is_zero(zrhs)) {
197+
goto zero_division_error;
198+
}
196199
mp_float_t flhs = mpz_as_float(zlhs);
197200
mp_float_t frhs = mpz_as_float(zrhs);
198201
return mp_obj_new_float(flhs / frhs);
@@ -216,6 +219,11 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
216219
break;
217220
case MP_BINARY_OP_FLOOR_DIVIDE:
218221
case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: {
222+
if (mpz_is_zero(zrhs)) {
223+
zero_division_error:
224+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError,
225+
"division by zero"));
226+
}
219227
mpz_t rem; mpz_init_zero(&rem);
220228
mpz_divmod_inpl(&res->mpz, &rem, zlhs, zrhs);
221229
if (zlhs->neg != zrhs->neg) {
@@ -229,6 +237,9 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
229237
}
230238
case MP_BINARY_OP_MODULO:
231239
case MP_BINARY_OP_INPLACE_MODULO: {
240+
if (mpz_is_zero(zrhs)) {
241+
goto zero_division_error;
242+
}
232243
mpz_t quo; mpz_init_zero(&quo);
233244
mpz_divmod_inpl(&quo, &res->mpz, zlhs, zrhs);
234245
mpz_deinit(&quo);
@@ -274,6 +285,9 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
274285
break;
275286

276287
case MP_BINARY_OP_DIVMOD: {
288+
if (mpz_is_zero(zrhs)) {
289+
goto zero_division_error;
290+
}
277291
mp_obj_int_t *quo = mp_obj_int_new_mpz();
278292
mpz_divmod_inpl(&quo->mpz, &res->mpz, zlhs, zrhs);
279293
// Check signs and do Python style modulo

py/runtime.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,9 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
389389

390390
case MP_BINARY_OP_MODULO:
391391
case MP_BINARY_OP_INPLACE_MODULO: {
392+
if (rhs_val == 0) {
393+
goto zero_division;
394+
}
392395
lhs_val = mp_small_int_modulo(lhs_val, rhs_val);
393396
break;
394397
}

tests/basics/builtin_divmod.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
except ZeroDivisionError:
1010
print("ZeroDivisionError")
1111

12+
try:
13+
divmod(1 << 65, 0)
14+
except ZeroDivisionError:
15+
print("ZeroDivisionError")
16+
1217
try:
1318
divmod('a', 'b')
1419
except TypeError:

tests/basics/int_big_error.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,13 @@
2929
i << (-(i >> 40))
3030
except ValueError:
3131
print('ValueError')
32+
33+
try:
34+
i // 0
35+
except ZeroDivisionError:
36+
print('ZeroDivisionError')
37+
38+
try:
39+
i % 0
40+
except ZeroDivisionError:
41+
print('ZeroDivisionError')

tests/basics/int_divzero.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,8 @@
22
1 // 0
33
except ZeroDivisionError:
44
print("ZeroDivisionError")
5+
6+
try:
7+
1 % 0
8+
except ZeroDivisionError:
9+
print("ZeroDivisionError")

tests/float/int_big_float.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,8 @@
1717

1818
# this should delegate to complex
1919
print("%.5g" % (i * 1.2j).imag)
20+
21+
try:
22+
i / 0
23+
except ZeroDivisionError:
24+
print("ZeroDivisionError")

0 commit comments

Comments
 (0)