Skip to content

Commit

Permalink
Fix & test for issue pybind#4288 (unicode surrogate character in Pyth…
Browse files Browse the repository at this point in the history
…on exception message).
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Oct 31, 2022
1 parent 5bc0943 commit 97b527a
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
18 changes: 17 additions & 1 deletion include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,23 @@ struct error_fetch_and_normalize {
message_error_string = detail::error_string();
result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
} else {
result = value_str.cast<std::string>();
// Not using `value_str.cast<std::string>()`, to not potentially throw a secondary
// error_already_set that will then result in process termination (#4288).
auto value_bytes = reinterpret_steal<object>(
PyUnicode_AsEncodedString(value_str.ptr(), "utf-8", "backslashreplace"));
if (!value_bytes) {
message_error_string = detail::error_string();
result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
} else {
char *buffer = nullptr;
Py_ssize_t length = 0;
if (PyBytes_AsStringAndSize(value_bytes.ptr(), &buffer, &length) == -1) {
message_error_string = detail::error_string();
result = "<MESSAGE UNAVAILABLE DUE TO ANOTHER EXCEPTION>";
} else {
result = std::string(buffer, static_cast<std::size_t>(length));
}
}
}
} else {
result = "<MESSAGE UNAVAILABLE>";
Expand Down
5 changes: 0 additions & 5 deletions tests/test_exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,6 @@ struct PythonAlreadySetInDestructor {
py::str s;
};

std::string error_already_set_what(const py::object &exc_type, const py::object &exc_value) {
PyErr_SetObject(exc_type.ptr(), exc_value.ptr());
return py::error_already_set().what();
}

TEST_SUBMODULE(exceptions, m) {
m.def("throw_std_exception",
[]() { throw std::runtime_error("This exception was intentionally thrown."); });
Expand Down
14 changes: 14 additions & 0 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,20 @@ def test_local_translator(msg):
assert msg(excinfo.value) == "this mod"


def test_error_already_set_message_with_unicode_surrogate(): # Issue #4288
assert m.error_already_set_what(RuntimeError, "\ud927") == (
"RuntimeError: \\ud927",
False,
)


def test_error_already_set_message_with_malformed_utf8():
assert m.error_already_set_what(RuntimeError, b"\x80") == (
"RuntimeError: b'\\x80'",
False,
)


class FlakyException(Exception):
def __init__(self, failure_point):
if failure_point == "failure_point_init":
Expand Down

0 comments on commit 97b527a

Please sign in to comment.