This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author josh.r
Recipients josh.r, vstinner
Date 2016-04-21.18:36:47
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1461263807.63.0.49330886523.issue26820@psf.upfronthosting.co.za>
In-reply-to
Content
PyObject_CallMethod explicitly documents that "The C arguments are described by a Py_BuildValue() format string that should produce a tuple." While PyObject_CallFunction doesn't document this requirement, it has the same behavior, and the same failures, as does the undocumented _PyObject_CallMethodId.

The issue is that, should someone pass a format string of "O", then the type of the subsequent argument determines the effect in a non-obvious way; when the argument comes from a caller, and the intent was to pass a single argument, this means that if the caller passes a non-tuple sequence, everything works, while passing a tuple tries to pass the contents of the tuple as sequential arguments. This inconsistency was the cause of both #26478 and #21209 (maybe others).

Assuming the API can't/shouldn't be changed, it should still be an error when a format string of "O" is passed and the argument is a non-tuple (because you've violated the spec; the result of BuildValue was not a tuple). Instead call_function_tail is silently rewrapping non-tuple args in a single element tuple.

I'm proposing that, in debug builds (and ideally release builds too), abstract.c's call_function_tail treat the "non-tuple" case as an error, rather than rewrapping in a single element tuple. This still allows the use case where the function is used inefficiently, but correctly (where the format string is "O" and the value is *always* a tuple that's supposed to be varargs; it should really just use PyObject_CallFunctionObjArgs/PyObject_CallMethodObjArgs/PyObject_CallObject or Id based optimized versions, but it's legal). But it will make the majority of cases where a user provided argument could be tuple or not fail fast, rather than silently behave themselves *until* they receive a tuple and misbehave.

Downside: It will require code changes for cases like PyObject_CallFunction(foo, "k", myunsigned);, where there was no risk of misbehavior, but those cases were also violating the spec, and should be fixable by changing the format string to wrap the single value in parens, e.g. "(k)".
History
Date User Action Args
2016-04-21 18:36:47josh.rsetrecipients: + josh.r, vstinner
2016-04-21 18:36:47josh.rsetmessageid: <1461263807.63.0.49330886523.issue26820@psf.upfronthosting.co.za>
2016-04-21 18:36:47josh.rlinkissue26820 messages
2016-04-21 18:36:47josh.rcreate