New submission from Josh Rosenberg:

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)".

----------
components: Interpreter Core
messages: 263929
nosy: haypo, josh.r
priority: normal
severity: normal
status: open
title: Prevent uses of format string based PyObject_Call* that do not produce 
tuple required by docs
versions: Python 3.5, Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26820>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to