diff --git a/docs/features/ub.md b/docs/features/ub.md index 6f9d5efe..19512e3d 100644 --- a/docs/features/ub.md +++ b/docs/features/ub.md @@ -11,4 +11,3 @@ These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined i 4. Type `T`'s `__new__` returns an object that is not an instance of `T`. 5. Call `__new__` with a type that is not a subclass of `type`. 6. `__eq__`, `__lt__` or `__contains__`, etc.. returns a value that is not a boolean. -7. Division by zero. \ No newline at end of file diff --git a/src/ceval.cpp b/src/ceval.cpp index 2458f9a5..60457fcc 100644 --- a/src/ceval.cpp +++ b/src/ceval.cpp @@ -330,6 +330,9 @@ __NEXT_STEP:; if(is_small_int(TOP()) && is_small_int(SECOND())){ \ _1 = POPX(); \ _0 = TOP(); \ + if constexpr(#op[0] == '/' || #op[0] == '%'){ \ + if(_py_sint(_1) == 0) ZeroDivisionError(); \ + } \ TOP() = VAR(_py_sint(_0) op _py_sint(_1)); \ DISPATCH(); \ } diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 6fa99362..ce2cee62 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -225,6 +225,7 @@ void init_builtins(VM* _vm) { if(is_int(args[0])){ i64 lhs = _CAST(i64, args[0]); i64 rhs = CAST(i64, args[1]); + if(rhs == 0) vm->ZeroDivisionError(); auto res = std::div(lhs, rhs); return VAR(Tuple({VAR(res.quot), VAR(res.rem)})); }else{ @@ -442,11 +443,13 @@ void init_builtins(VM* _vm) { _vm->bind__floordiv__(_vm->tp_int, [](VM* vm, PyObject* lhs_, PyObject* rhs_) { i64 rhs = CAST(i64, rhs_); + if(rhs == 0) vm->ZeroDivisionError(); return VAR(_CAST(i64, lhs_) / rhs); }); _vm->bind__mod__(_vm->tp_int, [](VM* vm, PyObject* lhs_, PyObject* rhs_) { i64 rhs = CAST(i64, rhs_); + if(rhs == 0) vm->ZeroDivisionError(); return VAR(_CAST(i64, lhs_) % rhs); }); diff --git a/tests/01_int.py b/tests/01_int.py index 824c2af8..40ea08d7 100644 --- a/tests/01_int.py +++ b/tests/01_int.py @@ -62,4 +62,40 @@ assert (-4)**13 == -67108864 assert ~3 == -4 assert ~-3 == 2 -assert ~0 == -1 \ No newline at end of file +assert ~0 == -1 + +try: + 1 // 0 + exit(1) +except ZeroDivisionError: + pass + +try: + 1 % 0 + exit(1) +except ZeroDivisionError: + pass + +try: + 2**60 // 0 + exit(1) +except ZeroDivisionError: + pass + +try: + 2**60 % 0 + exit(1) +except ZeroDivisionError: + pass + +try: + divmod(1, 0) + exit(1) +except ZeroDivisionError: + pass + +try: + divmod(2**60, 0) + exit(1) +except ZeroDivisionError: + pass