circuitpython/tests/stress/fun_call_limit.py
Damien George bd556b6996 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>
2022-04-01 09:20:42 +11:00

37 lines
930 B
Python

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