Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Include/internal/pycore_global_objects_fini_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Include/internal/pycore_global_strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(aclose)
STRUCT_FOR_ID(add)
STRUCT_FOR_ID(add_done_callback)
STRUCT_FOR_ID(add_note)
STRUCT_FOR_ID(adobe)
STRUCT_FOR_ID(after_in_child)
STRUCT_FOR_ID(after_in_parent)
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_runtime_init_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Include/internal/pycore_unicodeobject_generated.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions Lib/test/test_pyexpat.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,34 @@ def _test_exception(self, have_source):
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):
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
27 changes: 27 additions & 0 deletions Modules/pyexpat.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,29 @@ 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);
Comment thread
picnixz marked this conversation as resolved.
if (note == NULL) {
goto error;
}
PyObject *res = PyObject_CallMethodOneArg(exc, &_Py_ID(add_note), note);
Comment thread
picnixz marked this conversation as resolved.
Outdated
Py_DECREF(note);
if (res == NULL) {
goto error;
}
Py_DECREF(res);
goto done;
Comment thread
picnixz marked this conversation as resolved.

error:
PyErr_Clear();
done:
_PyErr_ChainExceptions1(exc);
}

#define RC_HANDLER(RETURN_TYPE, NAME, PARAMS, \
INIT, PARSE_FORMAT, CONVERSION, \
RETURN_VARIABLE, GETUSERDATA) \
Expand Down Expand Up @@ -536,6 +559,10 @@ my_ ## NAME ## Handler PARAMS { \
} \
CONVERSION \
Py_DECREF(rv); \
if (PyErr_Occurred()) { \
invalid_expat_handler_rv(#NAME); \
return RETURN_VARIABLE; \
Comment thread
picnixz marked this conversation as resolved.
Outdated
} \
return RETURN_VARIABLE; \
}

Expand Down
Loading