summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_math.py16
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-03-06-06-12-37.bpo-39871.dCAj_2.rst3
-rw-r--r--Modules/mathmodule.c6
3 files changed, 24 insertions, 1 deletions
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py
index cc39402..4b848a5 100644
--- a/Lib/test/test_math.py
+++ b/Lib/test/test_math.py
@@ -1992,6 +1992,22 @@ class MathTests(unittest.TestCase):
with self.subTest(x=x):
self.assertEqual(math.ulp(-x), math.ulp(x))
+ def test_issue39871(self):
+ # A SystemError should not be raised if the first arg to atan2(),
+ # copysign(), or remainder() cannot be converted to a float.
+ class F:
+ def __float__(self):
+ self.converted = True
+ 1/0
+ for func in math.atan2, math.copysign, math.remainder:
+ y = F()
+ with self.assertRaises(TypeError):
+ func("not a number", y)
+
+ # There should not have been any attempt to convert the second
+ # argument to a float.
+ self.assertFalse(getattr(y, "converted", False))
+
# Custom assertions.
def assertIsNaN(self, value):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-03-06-06-12-37.bpo-39871.dCAj_2.rst b/Misc/NEWS.d/next/Core and Builtins/2020-03-06-06-12-37.bpo-39871.dCAj_2.rst
new file mode 100644
index 0000000..0b4c2e5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-03-06-06-12-37.bpo-39871.dCAj_2.rst
@@ -0,0 +1,3 @@
+Fix a possible :exc:`SystemError` in ``math.{atan2,copysign,remainder}()``
+when the first argument cannot be converted to a :class:`float`. Patch by
+Zachary Spytz.
diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
index 77e325c..2a73a98 100644
--- a/Modules/mathmodule.c
+++ b/Modules/mathmodule.c
@@ -1106,9 +1106,13 @@ math_2(PyObject *const *args, Py_ssize_t nargs,
if (!_PyArg_CheckPositional(funcname, nargs, 2, 2))
return NULL;
x = PyFloat_AsDouble(args[0]);
+ if (x == -1.0 && PyErr_Occurred()) {
+ return NULL;
+ }
y = PyFloat_AsDouble(args[1]);
- if ((x == -1.0 || y == -1.0) && PyErr_Occurred())
+ if (y == -1.0 && PyErr_Occurred()) {
return NULL;
+ }
errno = 0;
r = (*func)(x, y);
if (Py_IS_NAN(r)) {