Skip to content

Commit 2ec4bf2

Browse files
committed
[mypyc] Fix fastcall positional fast path when parser is uninitialized
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.
1 parent 5e83bd6 commit 2ec4bf2

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

mypyc/lib-rt/getargsfast.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
/* None of this is supported on Python 3.6 or earlier */
2222
#if PY_VERSION_HEX >= 0x03070000
2323

24+
#define PARSER_INITED(parser) ((parser)->kwtuple != NULL)
25+
2426
/* Forward */
2527
static int
2628
vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
@@ -93,7 +95,8 @@ CPyArg_ParseStackAndKeywordsSimple(PyObject *const *args, Py_ssize_t nargs, PyOb
9395
va_list va;
9496

9597
va_start(va, parser);
96-
if (kwnames == NULL && nargs >= parser->min && nargs <= parser->max) {
98+
if (kwnames == NULL && PARSER_INITED(parser) &&
99+
nargs >= parser->min && nargs <= parser->max) {
97100
// Fast path: correct number of positional arguments only
98101
PyObject **p;
99102
Py_ssize_t i;
@@ -124,7 +127,7 @@ parser_init(CPyArg_Parser *parser)
124127
PyObject *kwtuple;
125128

126129
assert(parser->keywords != NULL);
127-
if (parser->kwtuple != NULL) {
130+
if (PARSER_INITED(parser)) {
128131
return 1;
129132
}
130133

mypyc/test-data/run-functions.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,10 @@ assert onearg(*t) == 2
968968
d = {'x': 5}
969969
assert onearg(**d) == 6
970970

971+
# Test a bogus call to twoargs before any correct calls are made
972+
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
973+
twoargs()
974+
971975
assert twoargs(5, 'foo') == 8
972976
assert twoargs(4, y='foo') == 7
973977
assert twoargs(y='foo', x=7) == 10
@@ -1002,6 +1006,8 @@ with assertRaises(TypeError, "onearg() missing required argument 'x' (pos 1)"):
10021006
with assertRaises(TypeError, "onearg() takes at most 1 argument (2 given)"):
10031007
onearg(1, y=1)
10041008

1009+
with assertRaises(TypeError, "twoargs() missing required argument 'x' (pos 1)"):
1010+
twoargs()
10051011
with assertRaises(TypeError, "twoargs() missing required argument 'y' (pos 2)"):
10061012
twoargs(1)
10071013
with assertRaises(TypeError, 'twoargs() takes at most 2 arguments (3 given)'):

0 commit comments

Comments
 (0)