Skip to content

Commit a281d38

Browse files
committed
gh-127146 Emscripten: Fix segfaults in test suite
After this, Emscripten makes it all the way through the test suite when I run it locally.
1 parent ff2278e commit a281d38

20 files changed

+57
-20
lines changed

Lib/test/list_tests.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
"""
44

55
import sys
6+
import unittest
67
from functools import cmp_to_key
78

89
from test import seq_tests
9-
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit
10+
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit, is_emscripten
1011

1112

1213
class CommonTest(seq_tests.CommonTest):
@@ -59,6 +60,7 @@ def test_repr(self):
5960
self.assertEqual(str(a2), "[0, 1, 2, [...], 3]")
6061
self.assertEqual(repr(a2), "[0, 1, 2, [...], 3]")
6162

63+
@unittest.skipIf(is_emscripten, "Stack overflow")
6264
def test_repr_deep(self):
6365
a = self.type2test([])
6466
for i in range(get_c_recursion_limit() + 1):

Lib/test/mapping_tests.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# tests common to dict and UserDict
22
import unittest
33
import collections
4-
from test.support import get_c_recursion_limit
4+
from test.support import get_c_recursion_limit, is_emscripten
55

66

77
class BasicTestMappingProtocol(unittest.TestCase):
@@ -622,6 +622,7 @@ def __repr__(self):
622622
d = self._full_mapping({1: BadRepr()})
623623
self.assertRaises(Exc, repr, d)
624624

625+
@unittest.skipIf(is_emscripten, "Stack overflow")
625626
def test_repr_deep(self):
626627
d = self._empty_mapping()
627628
for i in range(get_c_recursion_limit() + 1):

Lib/test/test_ast/test_ast.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
_testinternalcapi = None
1919

2020
from test import support
21-
from test.support import os_helper, script_helper
21+
from test.support import os_helper, script_helper, is_emscripten
2222
from test.support.ast_helper import ASTTestMixin
2323
from test.test_ast.utils import to_tuple
2424
from test.test_ast.snippets import (
@@ -745,6 +745,7 @@ def next(self):
745745
enum._test_simple_enum(_Precedence, ast._Precedence)
746746

747747
@support.cpython_only
748+
@unittest.skipIf(is_emscripten, "Stack overflow")
748749
def test_ast_recursion_limit(self):
749750
fail_depth = support.exceeds_recursion_limit()
750751
crash_depth = 100_000
@@ -1661,13 +1662,15 @@ def test_level_as_none(self):
16611662
exec(code, ns)
16621663
self.assertIn('sleep', ns)
16631664

1665+
@unittest.skipIf(is_emscripten, "Stack overflow")
16641666
def test_recursion_direct(self):
16651667
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
16661668
e.operand = e
16671669
with self.assertRaises(RecursionError):
16681670
with support.infinite_recursion():
16691671
compile(ast.Expression(e), "<test>", "eval")
16701672

1673+
@unittest.skipIf(is_emscripten, "Stack overflow")
16711674
def test_recursion_indirect(self):
16721675
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
16731676
f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))

Lib/test/test_call.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
2-
from test.support import (cpython_only, is_wasi, requires_limited_api, Py_DEBUG,
3-
set_recursion_limit, skip_on_s390x)
2+
from test.support import (cpython_only, is_wasi, is_emscripten, requires_limited_api,
3+
Py_DEBUG, set_recursion_limit, skip_on_s390x)
44
try:
55
import _testcapi
66
except ImportError:
@@ -1038,6 +1038,7 @@ class TestRecursion(unittest.TestCase):
10381038
@skip_on_s390x
10391039
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
10401040
@unittest.skipIf(_testcapi is None, "requires _testcapi")
1041+
@unittest.skipIf(is_emscripten, "requires deep stack")
10411042
def test_super_deep(self):
10421043

10431044
def recurse(n):

Lib/test/test_capi/test_misc.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -2215,16 +2215,17 @@ def test_configured_settings(self):
22152215
self.assertEqual(settings, expected)
22162216

22172217
# expected to fail
2218-
for config in expected_to_fail:
2219-
kwargs = dict(zip(kwlist, config))
2220-
with self.subTest(config):
2221-
script = textwrap.dedent(f'''
2222-
import _testinternalcapi
2223-
_testinternalcapi.get_interp_settings()
2224-
raise NotImplementedError('unreachable')
2225-
''')
2226-
with self.assertRaises(_interpreters.InterpreterError):
2227-
support.run_in_subinterp_with_config(script, **kwargs)
2218+
if _interpreters is not None:
2219+
for config in expected_to_fail:
2220+
kwargs = dict(zip(kwlist, config))
2221+
with self.subTest(config):
2222+
script = textwrap.dedent(f'''
2223+
import _testinternalcapi
2224+
_testinternalcapi.get_interp_settings()
2225+
raise NotImplementedError('unreachable')
2226+
''')
2227+
with self.assertRaises(_interpreters.InterpreterError):
2228+
support.run_in_subinterp_with_config(script, **kwargs)
22282229

22292230
@unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
22302231
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")

Lib/test/test_class.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"Test the functionality of Python classes implementing operators."
22

33
import unittest
4-
from test.support import cpython_only, import_helper, script_helper
4+
from test.support import cpython_only, import_helper, script_helper, is_emscripten
55

66
testmeths = [
77

@@ -554,6 +554,7 @@ class Custom:
554554
self.assertFalse(hasattr(o, "__call__"))
555555
self.assertFalse(hasattr(c, "__call__"))
556556

557+
@unittest.skipIf(is_emscripten, "exhausts limited stack")
557558
def testSFBug532646(self):
558559
# Test for SF bug 532646
559560

Lib/test/test_compile.py

+2
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ def __getitem__(self, key):
121121
self.assertEqual(d['z'], 12)
122122

123123
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
124+
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
124125
def test_extended_arg(self):
125126
repeat = int(get_c_recursion_limit() * 0.9)
126127
longexpr = 'x = x or ' + '-x' * repeat
@@ -709,6 +710,7 @@ def test_yet_more_evil_still_undecodable(self):
709710

710711
@support.cpython_only
711712
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
713+
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
712714
def test_compiler_recursion_limit(self):
713715
# Expected limit is Py_C_RECURSION_LIMIT
714716
limit = get_c_recursion_limit()

Lib/test/test_copy.py

+3
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ def test_deepcopy_list(self):
371371
self.assertIsNot(x, y)
372372
self.assertIsNot(x[0], y[0])
373373

374+
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
374375
def test_deepcopy_reflexive_list(self):
375376
x = []
376377
x.append(x)
@@ -398,6 +399,7 @@ def test_deepcopy_tuple_of_immutables(self):
398399
y = copy.deepcopy(x)
399400
self.assertIs(x, y)
400401

402+
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
401403
def test_deepcopy_reflexive_tuple(self):
402404
x = ([],)
403405
x[0].append(x)
@@ -415,6 +417,7 @@ def test_deepcopy_dict(self):
415417
self.assertIsNot(x, y)
416418
self.assertIsNot(x["foo"], y["foo"])
417419

420+
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
418421
def test_deepcopy_reflexive_dict(self):
419422
x = {}
420423
x['foo'] = x

Lib/test/test_descr.py

+3
Original file line numberDiff line numberDiff line change
@@ -3663,6 +3663,7 @@ def f(a): return a
36633663
encoding='latin1', errors='replace')
36643664
self.assertEqual(ba, b'abc\xbd?')
36653665

3666+
@unittest.skipIf(support.is_emscripten, "exhasts limited stack")
36663667
def test_recursive_call(self):
36673668
# Testing recursive __call__() by setting to instance of class...
36683669
class A(object):
@@ -3942,6 +3943,7 @@ def __del__(self):
39423943
# it as a leak.
39433944
del C.__del__
39443945

3946+
@unittest.skipIf(support.is_emscripten, "Seems to works in Pyodide?")
39453947
def test_slots_trash(self):
39463948
# Testing slot trash...
39473949
# Deallocating deeply nested slotted trash caused stack overflows
@@ -4864,6 +4866,7 @@ class Thing:
48644866
# CALL_METHOD_DESCRIPTOR_O
48654867
deque.append(thing, thing)
48664868

4869+
@unittest.skipIf(support.is_emscripten, "Stack overflow")
48674870
def test_repr_as_str(self):
48684871
# Issue #11603: crash or infinite loop when rebinding __str__ as
48694872
# __repr__.

Lib/test/test_dict.py

+1
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ def __repr__(self):
594594
d = {1: BadRepr()}
595595
self.assertRaises(Exc, repr, d)
596596

597+
@unittest.skipIf(support.is_emscripten, "Exhausts limited stack")
597598
def test_repr_deep(self):
598599
d = {}
599600
for i in range(get_c_recursion_limit() + 1):

Lib/test/test_dictviews.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import copy
33
import pickle
44
import unittest
5-
from test.support import get_c_recursion_limit
5+
from test.support import get_c_recursion_limit, is_emscripten
66

77
class DictSetTest(unittest.TestCase):
88

@@ -277,6 +277,7 @@ def test_recursive_repr(self):
277277
# Again.
278278
self.assertIsInstance(r, str)
279279

280+
@unittest.skipIf(is_emscripten, "exhausts limited stack")
280281
def test_deeply_nested_repr(self):
281282
d = {}
282283
for i in range(get_c_recursion_limit()//2 + 100):

Lib/test/test_exception_group.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import collections.abc
22
import types
33
import unittest
4-
from test.support import get_c_recursion_limit
4+
from test.support import get_c_recursion_limit, is_emscripten
55

66
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
77
def test_exception_group_types(self):
@@ -464,11 +464,13 @@ def make_deep_eg(self):
464464
e = ExceptionGroup('eg', [e])
465465
return e
466466

467+
@unittest.skipIf(is_emscripten, "exhausts limited stack")
467468
def test_deep_split(self):
468469
e = self.make_deep_eg()
469470
with self.assertRaises(RecursionError):
470471
e.split(TypeError)
471472

473+
@unittest.skipIf(is_emscripten, "exhausts limited stack")
472474
def test_deep_subgroup(self):
473475
e = self.make_deep_eg()
474476
with self.assertRaises(RecursionError):

Lib/test/test_functools.py

+2
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ def test_setstate_subclasses(self):
404404
self.assertEqual(r, ((1, 2), {}))
405405
self.assertIs(type(r[0]), tuple)
406406

407+
@unittest.skipIf(support.is_emscripten, "limited C stack")
407408
def test_recursive_pickle(self):
408409
with replaced_module('functools', self.module):
409410
f = self.partial(capture)
@@ -2054,6 +2055,7 @@ def orig(a, /, b, c=True): ...
20542055

20552056
@support.skip_on_s390x
20562057
@unittest.skipIf(support.is_wasi, "WASI has limited C stack")
2058+
@unittest.skipIf(support.is_emscripten, "limited C stack")
20572059
def test_lru_recursion(self):
20582060

20592061
@self.module.lru_cache

Lib/test/test_isinstance.py

+3
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,14 @@ def test_subclass_tuple(self):
263263
self.assertEqual(True, issubclass(int, (int, (float, int))))
264264
self.assertEqual(True, issubclass(str, (str, (Child, str))))
265265

266+
@unittest.skipIf(support.is_emscripten, "limited C stack")
266267
def test_subclass_recursion_limit(self):
267268
# make sure that issubclass raises RecursionError before the C stack is
268269
# blown
269270
with support.infinite_recursion():
270271
self.assertRaises(RecursionError, blowstack, issubclass, str, str)
271272

273+
@unittest.skipIf(support.is_emscripten, "limited C stack")
272274
def test_isinstance_recursion_limit(self):
273275
# make sure that issubclass raises RecursionError before the C stack is
274276
# blown
@@ -315,6 +317,7 @@ def __bases__(self):
315317
self.assertRaises(RecursionError, issubclass, int, X())
316318
self.assertRaises(RecursionError, isinstance, 1, X())
317319

320+
@unittest.skipIf(support.is_emscripten, "limited C stack")
318321
def test_infinite_recursion_via_bases_tuple(self):
319322
"""Regression test for bpo-30570."""
320323
class Failure(object):

Lib/test/test_json/test_recursion.py

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from test import support
22
from test.test_json import PyTest, CTest
3+
import unittest
34

45

56
class JSONTestObject:
@@ -68,6 +69,7 @@ def default(self, o):
6869
self.fail("didn't raise ValueError on default recursion")
6970

7071

72+
@unittest.skipIf(support.is_emscripten, "limited C stack")
7173
def test_highly_nested_objects_decoding(self):
7274
# test that loading highly-nested objects doesn't segfault when C
7375
# accelerations are used. See #12017
@@ -81,6 +83,7 @@ def test_highly_nested_objects_decoding(self):
8183
with support.infinite_recursion():
8284
self.loads('[' * 100000 + '1' + ']' * 100000)
8385

86+
@unittest.skipIf(support.is_emscripten, "limited C stack")
8487
def test_highly_nested_objects_encoding(self):
8588
# See #12051
8689
l, d = [], {}
@@ -93,6 +96,7 @@ def test_highly_nested_objects_encoding(self):
9396
with support.infinite_recursion(5000):
9497
self.dumps(d)
9598

99+
@unittest.skipIf(support.is_emscripten, "limited C stack")
96100
def test_endless_recursion(self):
97101
# See #12051
98102
class EndlessJSONEncoder(self.json.JSONEncoder):

Lib/test/test_pathlib/test_pathlib_abc.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pathlib._abc import UnsupportedOperation, ParserBase, PurePathBase, PathBase
1010
import posixpath
1111

12-
from test.support import is_wasi
12+
from test.support import is_wasi, is_emscripten
1313
from test.support.os_helper import TESTFN
1414

1515

@@ -2301,6 +2301,7 @@ def _check(path, pattern, case_sensitive, expected):
23012301
_check(path, "dirb/file*", False, ["dirB/fileB"])
23022302

23032303
@needs_symlinks
2304+
@unittest.skipIf(is_emscripten, "Hangs")
23042305
def test_glob_recurse_symlinks_common(self):
23052306
def _check(path, glob, expected):
23062307
actual = {path for path in path.glob(glob, recurse_symlinks=True)
@@ -2396,6 +2397,7 @@ def test_rglob_windows(self):
23962397
self.assertEqual(set(p.rglob("*\\")), { P(self.base, "dirC/dirD/") })
23972398

23982399
@needs_symlinks
2400+
@unittest.skipIf(is_emscripten, "Hangs")
23992401
def test_rglob_recurse_symlinks_common(self):
24002402
def _check(path, glob, expected):
24012403
actual = {path for path in path.rglob(glob, recurse_symlinks=True)

Lib/test/test_traceback.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from test.support.os_helper import TESTFN, unlink
2222
from test.support.script_helper import assert_python_ok, assert_python_failure
2323
from test.support.import_helper import forget
24-
from test.support import force_not_colorized
24+
from test.support import force_not_colorized, is_emscripten
2525

2626
import json
2727
import textwrap
@@ -2097,6 +2097,7 @@ def deep_eg(self):
20972097
return e
20982098

20992099
@cpython_only
2100+
@unittest.skipIf(is_emscripten, "Fails")
21002101
def test_exception_group_deep_recursion_capi(self):
21012102
from _testcapi import exception_print
21022103
LIMIT = 75
@@ -2108,6 +2109,7 @@ def test_exception_group_deep_recursion_capi(self):
21082109
self.assertIn('ExceptionGroup', output)
21092110
self.assertLessEqual(output.count('ExceptionGroup'), LIMIT)
21102111

2112+
@unittest.skipIf(is_emscripten, "Fails")
21112113
def test_exception_group_deep_recursion_traceback(self):
21122114
LIMIT = 75
21132115
eg = self.deep_eg()

Lib/test/test_xml_etree_c.py

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def test_del_attribute(self):
5757
del element.attrib
5858
self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})
5959

60+
@unittest.skipIf(support.is_emscripten, "segfaults")
6061
def test_trashcan(self):
6162
# If this test fails, it will most likely die via segfault.
6263
e = root = cET.Element('root')

configure

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

+1
Original file line numberDiff line numberDiff line change
@@ -2329,6 +2329,7 @@ AS_CASE([$ac_sys_system],
23292329
dnl Include file system support
23302330
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"])
23312331
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sEXPORTED_RUNTIME_METHODS=FS"])
2332+
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sSTACK_SIZE=5MB"])
23322333
23332334
AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [
23342335
AS_VAR_APPEND([LINKFORSHARED], [" -sMAIN_MODULE"])

0 commit comments

Comments
 (0)