From c520ce2f48d474cf43f40dadb57b95cf4082032e Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Sun, 5 Jan 2025 23:30:43 -0500 Subject: [PATCH 1/2] Protect against sendError() containing invalid utf-8 characters - Fixes #113 --- subprojects/robotpy-hal/hal/src/hal.cpp | 17 ++++++++++++++++- subprojects/robotpy-hal/tests/test_hal.py | 6 ++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/subprojects/robotpy-hal/hal/src/hal.cpp b/subprojects/robotpy-hal/hal/src/hal.cpp index 09a9ba1df..9df839130 100644 --- a/subprojects/robotpy-hal/hal/src/hal.cpp +++ b/subprojects/robotpy-hal/hal/src/hal.cpp @@ -66,14 +66,29 @@ RPYBUILD_PYBIND11_MODULE(m) { #else m.attr("__halplatform__") = "sim"; m.attr("__hal_simulation__") = true; + + m.def("__test_senderr", []() { + HAL_SendError(1, 2, 0, "\xfa" "badmessage", "location", "callstack", 1); + }, release_gil()); + #endif // Redirect stderr to python stderr sys_module = py::module_::import("sys"); HAL_SetPrintErrorImpl([](const char *line, size_t size) { + if (size == 0) { + return; + } + py::gil_scoped_acquire lock; - py::print(py::str(line, size), "file"_a=sys_module.attr("stderr")); + PyObject *o = PyUnicode_DecodeUTF8(line, size, "replace"); + if (o == nullptr) { + PyErr_Clear(); + py::print(py::bytes(line, size), "file"_a=sys_module.attr("stderr")); + } else { + py::print(py::reinterpret_steal(o), "file"_a=sys_module.attr("stderr")); + } }); // Do cleanup on module unload diff --git a/subprojects/robotpy-hal/tests/test_hal.py b/subprojects/robotpy-hal/tests/test_hal.py index 70a79c1aa..0846f69bd 100644 --- a/subprojects/robotpy-hal/tests/test_hal.py +++ b/subprojects/robotpy-hal/tests/test_hal.py @@ -9,3 +9,9 @@ def test_hal_simdevice(): v.set(4) assert v.get() == 4 + + +def test_hal_send_error(capsys): + hal._wpiHal.__test_senderr() + cap = capsys.readouterr() + assert cap.err == "Error at location: �badmessage\ncallstack\n\n" From 9a82c415e7f358f4b596af9e0e4ebfad2091b94f Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Sun, 5 Jan 2025 23:30:50 -0500 Subject: [PATCH 2/2] reportError doesn't need to convert strings to bytes .. underlying function takes strings --- subprojects/robotpy-wpilib/wpilib/_impl/report_error.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/subprojects/robotpy-wpilib/wpilib/_impl/report_error.py b/subprojects/robotpy-wpilib/wpilib/_impl/report_error.py index 50005d0da..f9e447dce 100644 --- a/subprojects/robotpy-wpilib/wpilib/_impl/report_error.py +++ b/subprojects/robotpy-wpilib/wpilib/_impl/report_error.py @@ -62,9 +62,9 @@ def reportErrorInternal( not isWarning, code, False, - error.encode("utf-8"), - locString.encode("utf-8"), - traceString.encode("utf-8"), + error, + locString, + traceString, True, )