Skip to content

Commit

Permalink
gh-127146 Emscripten: Skip segfaults in test suite
Browse files Browse the repository at this point in the history
After this, Emscripten makes it all the way through the test suite when I run it
locally.
  • Loading branch information
hoodmane committed Nov 23, 2024
1 parent ff2278e commit c6425ea
Show file tree
Hide file tree
Showing 20 changed files with 57 additions and 20 deletions.
4 changes: 3 additions & 1 deletion Lib/test/list_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
"""

import sys
import unittest
from functools import cmp_to_key

from test import seq_tests
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit, is_emscripten


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

@unittest.skipIf(is_emscripten, "Stack overflow")
def test_repr_deep(self):
a = self.type2test([])
for i in range(get_c_recursion_limit() + 1):
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/mapping_tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# tests common to dict and UserDict
import unittest
import collections
from test.support import get_c_recursion_limit
from test.support import get_c_recursion_limit, is_emscripten


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

@unittest.skipIf(is_emscripten, "Stack overflow")
def test_repr_deep(self):
d = self._empty_mapping()
for i in range(get_c_recursion_limit() + 1):
Expand Down
5 changes: 4 additions & 1 deletion Lib/test/test_ast/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
_testinternalcapi = None

from test import support
from test.support import os_helper, script_helper
from test.support import os_helper, script_helper, is_emscripten
from test.support.ast_helper import ASTTestMixin
from test.test_ast.utils import to_tuple
from test.test_ast.snippets import (
Expand Down Expand Up @@ -745,6 +745,7 @@ def next(self):
enum._test_simple_enum(_Precedence, ast._Precedence)

@support.cpython_only
@unittest.skipIf(is_emscripten, "Stack overflow")
def test_ast_recursion_limit(self):
fail_depth = support.exceeds_recursion_limit()
crash_depth = 100_000
Expand Down Expand Up @@ -1661,13 +1662,15 @@ def test_level_as_none(self):
exec(code, ns)
self.assertIn('sleep', ns)

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

@unittest.skipIf(is_emscripten, "Stack overflow")
def test_recursion_indirect(self):
e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0, operand=ast.Constant(1))
Expand Down
5 changes: 3 additions & 2 deletions Lib/test/test_call.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import unittest
from test.support import (cpython_only, is_wasi, requires_limited_api, Py_DEBUG,
set_recursion_limit, skip_on_s390x)
from test.support import (cpython_only, is_wasi, is_emscripten, requires_limited_api,
Py_DEBUG, set_recursion_limit, skip_on_s390x)
try:
import _testcapi
except ImportError:
Expand Down Expand Up @@ -1038,6 +1038,7 @@ class TestRecursion(unittest.TestCase):
@skip_on_s390x
@unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
@unittest.skipIf(_testcapi is None, "requires _testcapi")
@unittest.skipIf(is_emscripten, "requires deep stack")
def test_super_deep(self):

def recurse(n):
Expand Down
21 changes: 11 additions & 10 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2215,16 +2215,17 @@ def test_configured_settings(self):
self.assertEqual(settings, expected)

# expected to fail
for config in expected_to_fail:
kwargs = dict(zip(kwlist, config))
with self.subTest(config):
script = textwrap.dedent(f'''
import _testinternalcapi
_testinternalcapi.get_interp_settings()
raise NotImplementedError('unreachable')
''')
with self.assertRaises(_interpreters.InterpreterError):
support.run_in_subinterp_with_config(script, **kwargs)
if _interpreters is not None:
for config in expected_to_fail:
kwargs = dict(zip(kwlist, config))
with self.subTest(config):
script = textwrap.dedent(f'''
import _testinternalcapi
_testinternalcapi.get_interp_settings()
raise NotImplementedError('unreachable')
''')
with self.assertRaises(_interpreters.InterpreterError):
support.run_in_subinterp_with_config(script, **kwargs)

@unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_class.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"Test the functionality of Python classes implementing operators."

import unittest
from test.support import cpython_only, import_helper, script_helper
from test.support import cpython_only, import_helper, script_helper, is_emscripten

testmeths = [

Expand Down Expand Up @@ -554,6 +554,7 @@ class Custom:
self.assertFalse(hasattr(o, "__call__"))
self.assertFalse(hasattr(c, "__call__"))

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

Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def __getitem__(self, key):
self.assertEqual(d['z'], 12)

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

@support.cpython_only
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
def test_compiler_recursion_limit(self):
# Expected limit is Py_C_RECURSION_LIMIT
limit = get_c_recursion_limit()
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_copy.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,7 @@ def test_deepcopy_list(self):
self.assertIsNot(x, y)
self.assertIsNot(x[0], y[0])

@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
def test_deepcopy_reflexive_list(self):
x = []
x.append(x)
Expand Down Expand Up @@ -398,6 +399,7 @@ def test_deepcopy_tuple_of_immutables(self):
y = copy.deepcopy(x)
self.assertIs(x, y)

@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
def test_deepcopy_reflexive_tuple(self):
x = ([],)
x[0].append(x)
Expand All @@ -415,6 +417,7 @@ def test_deepcopy_dict(self):
self.assertIsNot(x, y)
self.assertIsNot(x["foo"], y["foo"])

@unittest.skipIf(support.is_emscripten, "exhausts limited stack")
def test_deepcopy_reflexive_dict(self):
x = {}
x['foo'] = x
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_descr.py
Original file line number Diff line number Diff line change
Expand Up @@ -3663,6 +3663,7 @@ def f(a): return a
encoding='latin1', errors='replace')
self.assertEqual(ba, b'abc\xbd?')

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

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

@unittest.skipIf(support.is_emscripten, "Stack overflow")
def test_repr_as_str(self):
# Issue #11603: crash or infinite loop when rebinding __str__ as
# __repr__.
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ def __repr__(self):
d = {1: BadRepr()}
self.assertRaises(Exc, repr, d)

@unittest.skipIf(support.is_emscripten, "Exhausts limited stack")
def test_repr_deep(self):
d = {}
for i in range(get_c_recursion_limit() + 1):
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_dictviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import copy
import pickle
import unittest
from test.support import get_c_recursion_limit
from test.support import get_c_recursion_limit, is_emscripten

class DictSetTest(unittest.TestCase):

Expand Down Expand Up @@ -277,6 +277,7 @@ def test_recursive_repr(self):
# Again.
self.assertIsInstance(r, str)

@unittest.skipIf(is_emscripten, "exhausts limited stack")
def test_deeply_nested_repr(self):
d = {}
for i in range(get_c_recursion_limit()//2 + 100):
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_exception_group.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import collections.abc
import types
import unittest
from test.support import get_c_recursion_limit
from test.support import get_c_recursion_limit, is_emscripten

class TestExceptionGroupTypeHierarchy(unittest.TestCase):
def test_exception_group_types(self):
Expand Down Expand Up @@ -464,11 +464,13 @@ def make_deep_eg(self):
e = ExceptionGroup('eg', [e])
return e

@unittest.skipIf(is_emscripten, "exhausts limited stack")
def test_deep_split(self):
e = self.make_deep_eg()
with self.assertRaises(RecursionError):
e.split(TypeError)

@unittest.skipIf(is_emscripten, "exhausts limited stack")
def test_deep_subgroup(self):
e = self.make_deep_eg()
with self.assertRaises(RecursionError):
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ def test_setstate_subclasses(self):
self.assertEqual(r, ((1, 2), {}))
self.assertIs(type(r[0]), tuple)

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

@support.skip_on_s390x
@unittest.skipIf(support.is_wasi, "WASI has limited C stack")
@unittest.skipIf(support.is_emscripten, "limited C stack")
def test_lru_recursion(self):

@self.module.lru_cache
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_isinstance.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,12 +263,14 @@ def test_subclass_tuple(self):
self.assertEqual(True, issubclass(int, (int, (float, int))))
self.assertEqual(True, issubclass(str, (str, (Child, str))))

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

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

@unittest.skipIf(support.is_emscripten, "limited C stack")
def test_infinite_recursion_via_bases_tuple(self):
"""Regression test for bpo-30570."""
class Failure(object):
Expand Down
4 changes: 4 additions & 0 deletions Lib/test/test_json/test_recursion.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from test import support
from test.test_json import PyTest, CTest
import unittest


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


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

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

@unittest.skipIf(support.is_emscripten, "limited C stack")
def test_endless_recursion(self):
# See #12051
class EndlessJSONEncoder(self.json.JSONEncoder):
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_pathlib/test_pathlib_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from pathlib._abc import UnsupportedOperation, ParserBase, PurePathBase, PathBase
import posixpath

from test.support import is_wasi
from test.support import is_wasi, is_emscripten
from test.support.os_helper import TESTFN


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

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

@needs_symlinks
@unittest.skipIf(is_emscripten, "Hangs")
def test_rglob_recurse_symlinks_common(self):
def _check(path, glob, expected):
actual = {path for path in path.rglob(glob, recurse_symlinks=True)
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from test.support.os_helper import TESTFN, unlink
from test.support.script_helper import assert_python_ok, assert_python_failure
from test.support.import_helper import forget
from test.support import force_not_colorized
from test.support import force_not_colorized, is_emscripten

import json
import textwrap
Expand Down Expand Up @@ -2097,6 +2097,7 @@ def deep_eg(self):
return e

@cpython_only
@unittest.skipIf(is_emscripten, "exhausts limited stack")
def test_exception_group_deep_recursion_capi(self):
from _testcapi import exception_print
LIMIT = 75
Expand All @@ -2108,6 +2109,7 @@ def test_exception_group_deep_recursion_capi(self):
self.assertIn('ExceptionGroup', output)
self.assertLessEqual(output.count('ExceptionGroup'), LIMIT)

@unittest.skipIf(is_emscripten, "exhausts limited stack")
def test_exception_group_deep_recursion_traceback(self):
LIMIT = 75
eg = self.deep_eg()
Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_xml_etree_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def test_del_attribute(self):
del element.attrib
self.assertEqual(element.attrib, {'A': 'B', 'C': 'D'})

@unittest.skipIf(support.is_emscripten, "segfaults")
def test_trashcan(self):
# If this test fails, it will most likely die via segfault.
e = root = cET.Element('root')
Expand Down
1 change: 1 addition & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,7 @@ AS_CASE([$ac_sys_system],
dnl Include file system support
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sFORCE_FILESYSTEM -lidbfs.js -lnodefs.js -lproxyfs.js -lworkerfs.js"])
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sEXPORTED_RUNTIME_METHODS=FS"])
AS_VAR_APPEND([LDFLAGS_NODIST], [" -sSTACK_SIZE=5MB"])
AS_VAR_IF([enable_wasm_dynamic_linking], [yes], [
AS_VAR_APPEND([LINKFORSHARED], [" -sMAIN_MODULE"])
Expand Down

0 comments on commit c6425ea

Please sign in to comment.