gh-146563: add exception note for invalid Expat handler return values (#146565)

This commit is contained in:
Bénédikt Tran
2026-04-14 19:12:47 +02:00
committed by GitHub
parent 4286227308
commit 356a031de5
4 changed files with 57 additions and 1 deletions
+2 -1
View File
@@ -29,7 +29,8 @@ PyAPI_FUNC(PyObject*) _PyErr_FormatFromCause(
...
);
extern int _PyException_AddNote(
// Export for 'pyexpat' shared extension.
PyAPI_FUNC(int) _PyException_AddNote(
PyObject *exc,
PyObject *note);
+28
View File
@@ -510,6 +510,34 @@ class HandlerExceptionTest(unittest.TestCase):
self.assertIn('call_with_frame("StartElement"',
entries[1].line)
def test_invalid_NotStandalone(self):
parser = expat.ParserCreate()
parser.NotStandaloneHandler = mock.Mock(return_value="bad value")
parser.ElementDeclHandler = lambda _1, _2: None
payload = b"""\
<!DOCTYPE quotations SYSTEM "quotations.dtd" [<!ELEMENT root ANY>]><root/>
"""
with self.assertRaises(TypeError) as cm:
parser.Parse(payload, True)
parser.NotStandaloneHandler.assert_called_once()
notes = ["invalid 'NotStandalone' event handler return value"]
self.assertEqual(cm.exception.__notes__, notes)
def test_invalid_ExternalEntityRefHandler(self):
parser = expat.ParserCreate()
parser.UseForeignDTD()
parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS)
parser.ExternalEntityRefHandler = mock.Mock(return_value=None)
with self.assertRaises(TypeError) as cm:
parser.Parse(b"<?xml version='1.0'?><element/>", True)
parser.ExternalEntityRefHandler.assert_called_once()
notes = ["invalid 'ExternalEntityRef' event handler return value"]
self.assertEqual(cm.exception.__notes__, notes)
# Test Current* members:
class PositionTest(unittest.TestCase):
@@ -0,0 +1,2 @@
:mod:`xml.parsers.expat`: add an exception note when a custom Expat handler
return value cannot be properly interpreted. Patch by Bénédikt Tran.
+25
View File
@@ -503,6 +503,28 @@ my_StartElementHandler(void *userData,
}
}
static inline void
invalid_expat_handler_rv(const char *name)
{
PyObject *exc = PyErr_GetRaisedException();
assert(exc != NULL);
PyObject *note = PyUnicode_FromFormat("invalid '%s' event handler return value", name);
if (note == NULL) {
goto error;
}
int rc = _PyException_AddNote(exc, note);
Py_DECREF(note);
if (rc < 0) {
goto error;
};
goto done;
error:
PyErr_Clear();
done:
PyErr_SetRaisedException(exc);
}
#define RC_HANDLER(RETURN_TYPE, NAME, PARAMS, \
INIT, PARSE_FORMAT, CONVERSION, \
RETURN_VARIABLE, GETUSERDATA) \
@@ -536,6 +558,9 @@ my_ ## NAME ## Handler PARAMS { \
} \
CONVERSION \
Py_DECREF(rv); \
if (PyErr_Occurred()) { \
invalid_expat_handler_rv(#NAME); \
} \
return RETURN_VARIABLE; \
}