summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2022-04-01 00:00:58 +1100
committerDamien George <damien@micropython.org>2022-04-01 09:20:42 +1100
commitbd556b69960cafc97353e736f825eca5c00b0c29 (patch)
treec92422308d39f738ecefeef4fed269b5fde2ddf7 /tests
parente3de723e2d955ca89c8b06bb2c4ae86724aad77b (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.py36
-rw-r--r--tests/stress/fun_call_limit.py.exp2
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