Skip to content

Commit 6bc217d

Browse files
committed
Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
1 parent 03863d2 commit 6bc217d

File tree

4 files changed

+58
-11
lines changed

4 files changed

+58
-11
lines changed

Lib/test/test_cmath.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test.support import run_unittest, requires_IEEE_754
1+
from test.support import run_unittest, requires_IEEE_754, cpython_only
22
from test.test_math import parse_testfile, test_file
33
import unittest
44
import cmath, math
@@ -381,17 +381,48 @@ def polar_complex(z):
381381
self.rAssertAlmostEqual(expected.imag, actual.imag,
382382
msg=error_message)
383383

384-
def assertCISEqual(self, a, b):
385-
eps = 1E-7
386-
if abs(a[0] - b[0]) > eps or abs(a[1] - b[1]) > eps:
387-
self.fail((a ,b))
384+
def check_polar(self, func):
385+
def check(arg, expected):
386+
got = func(arg)
387+
for e, g in zip(expected, got):
388+
self.rAssertAlmostEqual(e, g)
389+
check(0, (0., 0.))
390+
check(1, (1., 0.))
391+
check(-1, (1., pi))
392+
check(1j, (1., pi / 2))
393+
check(-3j, (3., -pi / 2))
394+
inf = float('inf')
395+
check(complex(inf, 0), (inf, 0.))
396+
check(complex(-inf, 0), (inf, pi))
397+
check(complex(3, inf), (inf, pi / 2))
398+
check(complex(5, -inf), (inf, -pi / 2))
399+
check(complex(inf, inf), (inf, pi / 4))
400+
check(complex(inf, -inf), (inf, -pi / 4))
401+
check(complex(-inf, inf), (inf, 3 * pi / 4))
402+
check(complex(-inf, -inf), (inf, -3 * pi / 4))
403+
nan = float('nan')
404+
check(complex(nan, 0), (nan, nan))
405+
check(complex(0, nan), (nan, nan))
406+
check(complex(nan, nan), (nan, nan))
407+
check(complex(inf, nan), (inf, nan))
408+
check(complex(-inf, nan), (inf, nan))
409+
check(complex(nan, inf), (inf, nan))
410+
check(complex(nan, -inf), (inf, nan))
388411

389412
def test_polar(self):
390-
self.assertCISEqual(polar(0), (0., 0.))
391-
self.assertCISEqual(polar(1.), (1., 0.))
392-
self.assertCISEqual(polar(-1.), (1., pi))
393-
self.assertCISEqual(polar(1j), (1., pi/2))
394-
self.assertCISEqual(polar(-1j), (1., -pi/2))
413+
self.check_polar(polar)
414+
415+
@cpython_only
416+
def test_polar_errno(self):
417+
# Issue #24489: check a previously set C errno doesn't disturb polar()
418+
from _testcapi import set_errno
419+
def polar_with_errno_set(z):
420+
set_errno(11)
421+
try:
422+
return polar(z)
423+
finally:
424+
set_errno(0)
425+
self.check_polar(polar_with_errno_set)
395426

396427
def test_phase(self):
397428
self.assertAlmostEqual(phase(0), 0.)

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ Core and Builtins
6060
Library
6161
-------
6262

63+
- Issue #24489: ensure a previously set C errno doesn't disturb cmath.polar().
64+
6365
- Issue #5633: Fixed timeit when the statement is a string and the setup is not.
6466

6567
- Issue #24326: Fixed audioop.ratecv() with non-default weightB argument.

Modules/_testcapimodule.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,18 @@ raise_exception(PyObject *self, PyObject *args)
17831783
return NULL;
17841784
}
17851785

1786+
static PyObject *
1787+
set_errno(PyObject *self, PyObject *args)
1788+
{
1789+
int new_errno;
1790+
1791+
if (!PyArg_ParseTuple(args, "i:set_errno", &new_errno))
1792+
return NULL;
1793+
1794+
errno = new_errno;
1795+
Py_RETURN_NONE;
1796+
}
1797+
17861798
static PyObject *
17871799
test_set_exc_info(PyObject *self, PyObject *args)
17881800
{
@@ -3208,6 +3220,7 @@ pymarshal_read_object_from_file(PyObject* self, PyObject *args)
32083220
static PyMethodDef TestMethods[] = {
32093221
{"raise_exception", raise_exception, METH_VARARGS},
32103222
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
3223+
{"set_errno", set_errno, METH_VARARGS},
32113224
{"test_config", (PyCFunction)test_config, METH_NOARGS},
32123225
{"test_sizeof_c_types", (PyCFunction)test_sizeof_c_types, METH_NOARGS},
32133226
{"test_datetime_capi", test_datetime_capi, METH_NOARGS},

Modules/cmathmodule.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,9 +941,10 @@ cmath_polar(PyObject *self, PyObject *args)
941941
double r, phi;
942942
if (!PyArg_ParseTuple(args, "D:polar", &z))
943943
return NULL;
944+
errno = 0;
944945
PyFPE_START_PROTECT("polar function", return 0)
945946
phi = c_atan2(z); /* should not cause any exception */
946-
r = c_abs(z); /* sets errno to ERANGE on overflow; otherwise 0 */
947+
r = c_abs(z); /* sets errno to ERANGE on overflow */
947948
PyFPE_END_PROTECT(r)
948949
if (errno != 0)
949950
return math_error();

0 commit comments

Comments
 (0)