Skip to content

Commit

Permalink
[mypyc] Fix fastcall positional fast path when parser is uninitialized
Browse files Browse the repository at this point in the history
In `CPyArg_ParseStackAndKeywordsSimple`, we don't check if the parser is
initialized, so on the first call, `min` and `max` will be zero and so
zero arguments being passed will always pass the test. Add an initialization
check.

Fixes #872.
  • Loading branch information
msullivan committed Jul 17, 2021
1 parent 5e83bd6 commit 2ec4bf2
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 2 deletions.
7 changes: 5 additions & 2 deletions mypyc/lib-rt/getargsfast.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
/* None of this is supported on Python 3.6 or earlier */
#if PY_VERSION_HEX >= 0x03070000

#define PARSER_INITED(parser) ((parser)->kwtuple != NULL)

/* Forward */
static int
vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
Expand Down Expand Up @@ -93,7 +95,8 @@ CPyArg_ParseStackAndKeywordsSimple(PyObject *const *args, Py_ssize_t nargs, PyOb
va_list va;

va_start(va, parser);
if (kwnames == NULL && nargs >= parser->min && nargs <= parser->max) {
if (kwnames == NULL && PARSER_INITED(parser) &&
nargs >= parser->min && nargs <= parser->max) {
// Fast path: correct number of positional arguments only
PyObject **p;
Py_ssize_t i;
Expand Down Expand Up @@ -124,7 +127,7 @@ parser_init(CPyArg_Parser *parser)
PyObject *kwtuple;

assert(parser->keywords != NULL);
if (parser->kwtuple != NULL) {
if (PARSER_INITED(parser)) {
return 1;
}

Expand Down
6 changes: 6 additions & 0 deletions mypyc/test-data/run-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,10 @@ assert onearg(*t) == 2
d = {'x': 5}
assert onearg(**d) == 6

# Test a bogus call to twoargs before any correct calls are made
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
twoargs()

assert twoargs(5, 'foo') == 8
assert twoargs(4, y='foo') == 7
assert twoargs(y='foo', x=7) == 10
Expand Down Expand Up @@ -1002,6 +1006,8 @@ with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
with assertRaises(TypeError, "onearg() takes at most 1 argument (2 given)"):
onearg(1, y=1)

with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
twoargs()
with assertRaises(TypeError, "twoargs() missing required argument 'y' (pos 2)"):
twoargs(1)
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):
Expand Down

0 comments on commit 2ec4bf2

Please sign in to comment.