[C++-sig] Segfault with keyword arguments and overloads.

Alex Mohr amohr at pixar.com
Thu Aug 8 20:05:20 CEST 2013


Oh!  I did miss your patch, sorry.  Thanks!

It looks to me like your patch calls PyTuple_GET_ITEM() with None as the 
python object (when kv is None).  The python docs for PyTuple_GET_ITEM 
say, "Like PyTuple_GetItem(), but does no checking of its arguments." 
To me that means that the object you pass really needs to be a tuple.

Here's the patch I'm using -- it simply checks to see if kv is None, 
which is true if the overload doesn't accept a keyword arg in that 
position, and if so it simply rejects the overload.  This is working for 
me in the example and across our codebase and testsuite.

I will file a bug as you suggest, and thanks again.

Alex

--- ./boost_1_53_0/libs/python/src/object/function.cpp.orig	2013-07-22 
17:38:54.000000000 -0700
+++ ./boost_1_53_0/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->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<>();
+                                break;
+                            }
+
                              // If there were any keyword arguments,
                              // look up the one we need for this
                              // argument position


On 8/8/2013 2:28 AM, Alex Leach wrote:
> Hi Alex,
>
> On Wed, 07 Aug 2013 18:06:24 +0100, Alex Mohr <amohr at pixar.com> wrote:
>
>> Thanks for your response.  I've responded to your comments in-line below.
>>
>> After further investigation, I believe this can be fixed by simply
>> checking for None when we get 'kv' from f->m_arg_names while resolving
>> keywords.  If we encounter None, that means the overload doesn't
>> accept a keyword argument in that position (so not enough positional
>> args were passed), and we can reject the overload.
>>
>> If it works, I think that's a simple, targeted fix that isn't
>> particularly risky.  I'll try to work up a patch.
>>
>
>
> Sounds like you missed it, but I did add a fairly simple patch to my
> previous email. I used your code as a test case and it worked fine; no
> seg faults. I've copied it again below...
>
> I don't have commit privileges to Boost Python, but I think from your
> explanations, that this is a valid bug in BP. So it would probably be
> worthwhile filing a bug report, at
> http://www.boost.org/development/bugs.html
>
> Unless someone with commit privileges wants to consider merging it? My
> only thought on the patch regards return value optimisation. Would
> moving the `PyObject *` declarations out of the loop impair the
> compiler's ability to perform RVO?
>
>
> Hope that helps anyway.
>
> Kind regards,
> Alex
>
>
> --- ./boost_1_53_0/libs/python/src/object/function.cpp.orig
> 2013-08-07 11:02:28.569236835 +0100
> +++ ./boost_1_53_0/libs/python/src/object/function.cpp  2013-08-07
> 11:56:10.926045853 +0100
> @@ -177,16 +177,18 @@
>                           // Grab remaining arguments by name from the
> keyword dictionary
>                           std::size_t n_actual_processed =
> n_unnamed_actual;
>
> +                        PyObject *kv, *k, *value;
>                           for (std::size_t arg_pos = n_unnamed_actual;
> arg_pos < max_arity ; ++arg_pos)
>                           {
>                               // Get the keyword[, value pair]
> corresponding
> -                            PyObject* kv =
> PyTuple_GET_ITEM(f->m_arg_names.ptr(), arg_pos);
> +                            kv = PyTuple_GET_ITEM(f->m_arg_names.ptr(),
> arg_pos);
>
>                               // If there were any keyword arguments,
>                               // look up the one we need for this
>                               // argument position
> -                            PyObject* value = n_keyword_actual
> -                                ? PyDict_GetItem(keywords,
> PyTuple_GET_ITEM(kv, 0))
> +                            k = PyTuple_GET_ITEM(kv, 0);
> +                            value = (k != NULL && n_keyword_actual)
> +                                ? PyDict_GetItem(keywords, k)
>                                   : 0;
>
>                               if (!value)



More information about the Cplusplus-sig mailing list