From e634a8ac1f8a2904a2241b83fc5e4c9f40d5c7ca Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 14 Mar 2020 11:38:52 +0000 Subject: [3.8] bpo-39871: Fix possible SystemError in atan2, copysign and remainder (GH-18806) (GH-18989) In math_2(), the first PyFloat_AsDouble() call should be checked for failure before the second call. Co-authored-by: Mark Dickinson . (cherry picked from commit 5208b4b37953a406db0ed6a9db545c2948dde989) Co-authored-by: Zackery Spytz --- Lib/test/test_math.py | 16 ++++++++++++++++ .../2020-03-06-06-12-37.bpo-39871.dCAj_2.rst | 3 +++ Modules/mathmodule.c | 6 +++++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-03-06-06-12-37.bpo-39871.dCAj_2.rst diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 6abaeea..4a1ba83 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -1878,6 +1878,22 @@ class MathTests(unittest.TestCase): self.assertIs(type(comb(IntSubclass(5), IntSubclass(k))), int) self.assertIs(type(comb(MyIndexable(5), MyIndexable(k))), int) + 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 4e97337..b78fced 100644 --- a/Modules/mathmodule.c +++ b/Modules/mathmodule.c @@ -1027,9 +1027,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; PyFPE_START_PROTECT("in math_2", return 0); r = (*func)(x, y); -- cgit v0.12