Skip to content

Commit 6f3ae87

Browse files
committed
pythongh-145966: Fix _csv DIALECT_GETATTR macro silently masking non-AttributeError exceptions
The DIALECT_GETATTR macro in dialect_new() unconditionally called PyErr_Clear() when PyObject_GetAttrString() failed, which suppressed all exceptions including MemoryError, KeyboardInterrupt, and RuntimeError. Now only AttributeError is cleared; other exceptions propagate via the existing error handling path.
1 parent e167e06 commit 6f3ae87

3 files changed

Lines changed: 25 additions & 2 deletions

File tree

Lib/test/test_csv.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,20 @@ class mydialect(csv.Dialect):
12811281
skipinitialspace=True)
12821282

12831283

1284+
def test_dialect_getattr_non_attribute_error_propagates(self):
1285+
# gh-145966: non-AttributeError exceptions raised by __getattr__
1286+
# during dialect attribute lookup must propagate, not be silenced.
1287+
class BadDialect:
1288+
def __getattr__(self, name):
1289+
raise RuntimeError("boom")
1290+
1291+
with self.assertRaises(RuntimeError):
1292+
csv.reader([], dialect=BadDialect())
1293+
1294+
with self.assertRaises(RuntimeError):
1295+
csv.writer(StringIO(), dialect=BadDialect())
1296+
1297+
12841298
class TestSniffer(unittest.TestCase):
12851299
sample1 = """\
12861300
Harry's, Arlington Heights, IL, 2/1/03, Kimi Hayes
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Fixed ``DIALECT_GETATTR`` macro in :mod:`csv` to only clear
2+
:exc:`AttributeError` exceptions. Previously, all exceptions (including
3+
:exc:`MemoryError` and :exc:`KeyboardInterrupt`) were silently suppressed
4+
when looking up dialect attributes.

Modules/_csv.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,13 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
501501
do { \
502502
if (v == NULL) { \
503503
v = PyObject_GetAttrString(dialect, n); \
504-
if (v == NULL) \
505-
PyErr_Clear(); \
504+
if (v == NULL) { \
505+
if (PyErr_ExceptionMatches( \
506+
PyExc_AttributeError)) \
507+
PyErr_Clear(); \
508+
else \
509+
goto err; \
510+
} \
506511
} \
507512
} while (0)
508513
DIALECT_GETATTR(delimiter, "delimiter");

0 commit comments

Comments
 (0)