pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.57k stars 2.09k forks source link

[BUG]: Python3.11 `error_already_set.what()` segfault #4853

Open Tishj opened 1 year ago

Tishj commented 1 year ago

Required prerequisites

What version (or hash if on master) of pybind11 are you using?

2.11.1

Problem description

I run an import of pyarrow and attempt to create a Table from a Pandas DataFrame

return py::module_::import("pyarrow").attr("lib").attr("Table").attr("from_pandas")(df);

this throws an exception, which I catch:

   103          } catch (py::error_already_set &e) {
-> 104                  throw InvalidInputException(
   105                      "The dataframe could not be converted to a pyarrow.lib.Table, due to the following python exception: %s",
   106                      e.what());
   107          }

py::error_already_set.what() causes the segfault.

Reproducible example code

I maintain an opensource repo and I absolutely hate it when I get an issue without a reproduction example, but in this case I can't really make one as it's wrapped into an application and only occurs when run together with multiple tests.

(Just running the test where the segfault occurs does not reproduce the issue)

I have however attached lldb and have a stacktrace that hopefully provides more information:

* thread #1, name = 'python3', stop reason = signal SIGSEGV: invalid address (fault address: 0xa8)
    frame #0: 0x00000000005a4e6c python3`PyFrame_GetBack + 44
python3`PyFrame_GetBack:
->  0x5a4e6c <+44>: ldrsw  x6, [x4, #0xa8]
    0x5a4e70 <+48>: add    x7, x3, x6, lsl #1
    0x5a4e74 <+52>: cmp    x5, x7
    0x5a4e78 <+56>: b.lo   0x5a4ecc                  ; <+140>
(lldb) up
error: duckdb.cpython-311-aarch64-linux-gnu.so 0x017e4a81: DW_TAG_member '_M_pod_data' refers to type 0x01912765 which extends beyond the bounds of 0x017e4a2c
frame #1: 0x0000fffff3892fa8 duckdb.cpython-311-aarch64-linux-gnu.so`pybind11::detail::error_fetch_and_normalize::format_value_and_trace[abi:cxx11](this=0x000000000262fd70) const at pytypes.h:657:48
   654                  result += '\n';
   655                  Py_DECREF(f_code);
   656  #    if PY_VERSION_HEX >= 0x030900B1
-> 657                  auto *b_frame = PyFrame_GetBack(frame);
   658  #    else
   659                  auto *b_frame = frame->f_back;
   660                  Py_XINCREF(b_frame);
(lldb) up
frame #2: 0x0000fffff3893298 duckdb.cpython-311-aarch64-linux-gnu.so`pybind11::detail::error_fetch_and_normalize::error_string[abi:cxx11](this=0x000000000262fd70) const at pytypes.h:682:65
   679 
   680      std::string const &error_string() const {
   681          if (!m_lazy_error_string_completed) {
-> 682              m_lazy_error_string += ": " + format_value_and_trace();
   683              m_lazy_error_string_completed = true;
   684          }
   685          return m_lazy_error_string;
(lldb) 
frame #3: 0x0000fffff38a7b00 duckdb.cpython-311-aarch64-linux-gnu.so`pybind11::error_already_set::what(this=0x000000000246c690) const at pybind11.h:2668:41
   2665 inline const char *error_already_set::what() const noexcept {
   2666     gil_scoped_acquire gil;
   2667     error_scope scope;
-> 2668     return m_fetched_error->error_string().c_str();
   2669 }
   2670
   2671 PYBIND11_NAMESPACE_BEGIN(detail)
(lldb) 
frame #4: 0x0000fffff39b2c14 duckdb.cpython-311-aarch64-linux-gnu.so`duckdb::ArrowTableFromDataframe(df=0x0000ffffffffb718) at pyconnection.cpp:104:3
   101          try {
   102                  return py::module_::import("pyarrow").attr("lib").attr("Table").attr("from_pandas")(df);
   103          } catch (py::error_already_set &e) {
-> 104                  throw InvalidInputException(
   105                      "The dataframe could not be converted to a pyarrow.lib.Table, due to the following python exception: %s",
   106                      e.what());
   107          }

Python version: Python 3.11.0rc1 (Docker) Linux version: Linux f63acc518afb 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 aarch64 aarch64 GNU/Linux

On Python3.9 the issue is not reproducable



### Is this a regression? Put the last known working version here if it is.

Not a regression
Tishj commented 1 year ago

I know it's not much of a reproduction, but if you could have a look at the stacktrace and theorycraft why this segfault occurs that would be extremely helpful already.

I can't figure out why PyFrame_GetBack would segfault here

Tishj commented 7 months ago

I think this is related to https://github.com/pybind/pybind11/pull/4863

aimxhaisse commented 4 months ago

Unsure if related / this is the same issue, but I can also reproduce it on indentation errors (python 3.11, pybind 2.12.0), here's the stacktrace:

#0  0x00007ffff714a9b0 in ?? () from /usr/lib/libpython3.11.so.1.0
#1  0x00007ffff7146d75 in PyErr_Format () from /usr/lib/libpython3.11.so.1.0
#2  0x00007ffff7136c7f in _PyObject_GenericGetAttrWithDict () from /usr/lib/libpython3.11.so.1.0
#3  0x00007ffff71414cd in PyObject_GetAttr () from /usr/lib/libpython3.11.so.1.0
#4  0x00007ffff71448d6 in PyObject_GetAttrString () from /usr/lib/libpython3.11.so.1.0
#5  0x00005555556d5d78 in pybind11::detail::error_fetch_and_normalize::format_value_and_trace[abi:cxx11]() const (this=0x7fff7c06b5a0)
    at /home/mxs/code/neon/deps/pybind11/include/pybind11/pytypes.h:588
#6  0x00005555556d68d6 in pybind11::detail::error_fetch_and_normalize::error_string[abi:cxx11]() const (this=0x7fff7c06b5a0)
    at /home/mxs/code/neon/deps/pybind11/include/pybind11/pytypes.h:682
#7  0x00005555556e36d0 in pybind11::error_already_set::what (this=0x7fff7c0628f0) at /home/mxs/code/neon/deps/pybind11/include/pybind11/pybind11.h:2668

And some info about the error:

(gdb) frame 7
#7  0x00005555556e36d0 in pybind11::error_already_set::what (this=0x7fff7c0628f0) at /home/mxs/code/neon/deps/pybind11/include/pybind11/pybind11.h:2668
2668        return m_fetched_error->error_string().c_str();

(gdb) p *m_fetched_error.get()
$3 = {
  m_type = {<pybind11::handle> = {<pybind11::detail::object_api<pybind11::handle>> = {<pybind11::detail::pyobject_tag> = {<No data fields>}, <No data fields>}, m_ptr = 0x7ffff745be80}, <No data fields>}, 
  m_value = {<pybind11::handle> = {<pybind11::detail::object_api<pybind11::handle>> = {<pybind11::detail::pyobject_tag> = {<No data fields>}, <No data fields>}, m_ptr = 0x7ffff4024200}, <No data fields>}, 
  m_trace = {<pybind11::handle> = {<pybind11::detail::object_api<pybind11::handle>> = {<pybind11::detail::pyobject_tag> = {<No data fields>}, <No data fields>}, m_ptr = 0x0}, <No data fields>}, m_lazy_error_string = "IndentationError", m_lazy_error_string_completed = false, m_restore_called = false}