diff options
| author | Damien George <damien@micropython.org> | 2022-04-01 00:00:58 +1100 |
|---|---|---|
| committer | Damien George <damien@micropython.org> | 2022-04-01 09:20:42 +1100 |
| commit | bd556b69960cafc97353e736f825eca5c00b0c29 (patch) | |
| tree | c92422308d39f738ecefeef4fed269b5fde2ddf7 /tests | |
| parent | e3de723e2d955ca89c8b06bb2c4ae86724aad77b (diff) | |
py: Fix compiling and decoding of *args at large arg positions.
There were two issues with the existing code:
1. "1 << i" is computed as a 32-bit number so would overflow when
executed on 64-bit machines (when mp_uint_t is 64-bit). This meant that
*args beyond 32 positions would not be handled correctly.
2. star_args must fit as a positive small int so that it is encoded
correctly in the emitted code. MP_SMALL_INT_BITS is too big because it
overflows a small int by 1 bit. MP_SMALL_INT_BITS - 1 does not work
because it produces a signed small int which is then sign extended when
extracted (even by mp_obj_get_int_truncated), and this sign extension
means that any position arg after *args is also treated as a star-arg.
So the maximum bit position is MP_SMALL_INT_BITS - 2. This means that
MP_OBJ_SMALL_INT_VALUE() can be used instead of
mp_obj_get_int_truncated() to get the value of star_args.
These issues are fixed by this commit, and a test added.
Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/stress/fun_call_limit.py | 36 | ||||
| -rw-r--r-- | tests/stress/fun_call_limit.py.exp | 2 |
2 files changed, 38 insertions, 0 deletions
diff --git a/tests/stress/fun_call_limit.py b/tests/stress/fun_call_limit.py new file mode 100644 index 000000000..b802aadd5 --- /dev/null +++ b/tests/stress/fun_call_limit.py @@ -0,0 +1,36 @@ +# Test the limit of the number of arguments to a function call. +# This currently tests the case of *args after many positional args. + + +def f(*args): + return len(args) + + +def test(n): + pos_args = ",".join(str(i) for i in range(n)) + s = "f({}, *(100, 101), 102, 103)".format(pos_args) + try: + return eval(s) + except SyntaxError: + return "SyntaxError" + + +# If the port has at least 32-bits then this test should pass. +print(test(29)) + +# This test should fail on all ports (overflows a small int). +print(test(70)) + +# Check that there is a correct transition to the limit of too many args before *args. +reached_limit = False +for i in range(30, 70): + result = test(i) + if reached_limit: + if result != "SyntaxError": + print("FAIL") + else: + if result == "SyntaxError": + reached_limit = True + else: + if result != i + 4: + print("FAIL") diff --git a/tests/stress/fun_call_limit.py.exp b/tests/stress/fun_call_limit.py.exp new file mode 100644 index 000000000..53d2b2804 --- /dev/null +++ b/tests/stress/fun_call_limit.py.exp @@ -0,0 +1,2 @@ +33 +SyntaxError |
