Boost C++ Libraries: Ticket #8978: Segfault crash in boost.python with keyword arguments and overloads. https://svn.boost.org/trac10/ticket/8978 <p> Please see the thread on the python c++ sig email list here (lacking protocol prefix to pass spam check): mail.python.org/pipermail/cplusplus-sig/2013-August/017012.html </p> <p> Here is a minimal repro case: </p> <hr /> <p> <em> C++ #include &lt;boost/python.hpp&gt; </em></p> <p> static void f1(int a0, int a1) { } static void f2(int a0, int a1, int a2) { } </p> <p> BOOST_PYTHON_MODULE(kwargCrash) { </p> <blockquote> <p> boost::python::def("f", f1, (arg("a1")=2)); boost::python::def("f", f2, (arg("a2")=2)); </p> </blockquote> <p> } </p> <p> # Python import kwargCrash kwargCrash.f(0, a1=2) </p> <hr /> <p> Version found info: boost 1.51.0, Python 2.7.5, gcc 4.8.1. </p> <p> Please see the list thread linked above for a detailed explanation of why the crash occurs. In short, boost.python calls PyTuple_GET_ITEM() on None, and then unconditionally uses the result as a key to look up in a dict. This boost.python code hasn't changed in a long time. I suspect Python has changed, and is now returning NULL here instead of None, and calling PyDict_GetItem with NULL crashes. </p> <p> Here is a patch to the boost.python code that fixes the bug. It simply checks to see if it got None from the m_arg_names tuple, and if so, that means the overload does not accept a keyword arg in that position, so it rejects the overload. This fixes the crash and works correctly across our codebase and testsuite. </p> <p> If the patch looks good, it would be great to apply it and add the repro case to the test suite. </p> <p> Thanks! </p> <p> --- ./libs/python/src/object/function.cpp.orig 2013-07-22 17:38:54.000000000 -0700 +++ ./libs/python/src/object/function.cpp 2013-08-07 10:25:26.963988000 -0700 @@ -182,6 +182,16 @@ </p> <blockquote> <p> <em> Get the keyword[, value pair] corresponding <a class="missing wiki">PyObject</a>* kv = PyTuple_GET_ITEM(f-&gt;m_arg_names.ptr(), arg_pos); </em></p> </blockquote> <p> + <em> If kv is None, this overload does not accept a + </em> keyword argument in this position, meaning that + <em> the caller did not supply enough positional + </em> arguments. Reject the overload. + if (kv == Py_None) { + PyErr_Clear(); + inner_args = handle&lt;&gt;(); + break; + } + </p> <blockquote> <p> <em> If there were any keyword arguments, </em> look up the one we need for this <em> argument position </em></p> </blockquote> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/8978 Trac 1.4.3 amohr@… Thu, 08 Aug 2013 18:32:27 GMT <link>https://svn.boost.org/trac10/ticket/8978#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/8978#comment:1</guid> <description> <p> Oh man, I didn't realize it would format my input. Here's the repro and patch again, hopefully better formatted. </p> <pre class="wiki">// C++ #include &lt;boost/python.hpp&gt; static void f1(int a0, int a1) { } static void f2(int a0, int a1, int a2) { } BOOST_PYTHON_MODULE(kwargCrash) { boost::python::def("f", f1, (arg("a1")=2)); boost::python::def("f", f2, (arg("a2")=2)); } # Python import kwargCrash kwargCrash.f(0, a1=2) --- ./libs/python/src/object/function.cpp.orig 2013-07-22 17:38:54.000000000 -0700 +++ ./libs/python/src/object/function.cpp 2013-08-07 10:25:26.963988000 -0700 @@ -182,6 +182,16 @@ // Get the keyword[, value pair] corresponding PyObject* kv = PyTuple_GET_ITEM(f-&gt;m_arg_names.ptr(), arg_pos); + // If kv is None, this overload does not accept a + // keyword argument in this position, meaning that + // the caller did not supply enough positional + // arguments. Reject the overload. + if (kv == Py_None) { + PyErr_Clear(); + inner_args = handle&lt;&gt;(); + break; + } + // If there were any keyword arguments, // look up the one we need for this // argument position </pre> </description> <category>Ticket</category> </item> </channel> </rss>