mirror of https://github.com/python/cpython
gh-90473: Decrease recursion limit and skip tests on WASI (GH-92803)
This commit is contained in:
parent
e48ac9c100
commit
137fd3d88a
|
@ -12,8 +12,14 @@ extern "C" {
|
|||
struct pyruntimestate;
|
||||
struct _ceval_runtime_state;
|
||||
|
||||
/* WASI has limited call stack. wasmtime 0.36 can handle sufficient amount of
|
||||
C stack frames for little more than 750 recursions. */
|
||||
#ifndef Py_DEFAULT_RECURSION_LIMIT
|
||||
# define Py_DEFAULT_RECURSION_LIMIT 1000
|
||||
# ifdef __wasi__
|
||||
# define Py_DEFAULT_RECURSION_LIMIT 750
|
||||
# else
|
||||
# define Py_DEFAULT_RECURSION_LIMIT 1000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "pycore_interp.h" // PyInterpreterState.eval_frame
|
||||
|
|
|
@ -186,6 +186,10 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384):
|
|||
|
||||
executable = sys.executable
|
||||
|
||||
if not executable:
|
||||
# sys.executable is not set.
|
||||
return lib, version
|
||||
|
||||
V = _comparable_version
|
||||
# We use os.path.realpath()
|
||||
# here to work around problems with Cygwin not being
|
||||
|
|
|
@ -545,8 +545,14 @@ def collect_ssl(info_add):
|
|||
def collect_socket(info_add):
|
||||
import socket
|
||||
|
||||
hostname = socket.gethostname()
|
||||
info_add('socket.hostname', hostname)
|
||||
try:
|
||||
hostname = socket.gethostname()
|
||||
except OSError:
|
||||
# WASI SDK 15.0 does not have gethostname(2).
|
||||
if sys.platform != "wasi":
|
||||
raise
|
||||
else:
|
||||
info_add('socket.hostname', hostname)
|
||||
|
||||
|
||||
def collect_sqlite(info_add):
|
||||
|
|
|
@ -199,6 +199,11 @@ def get_original_stdout():
|
|||
def _force_run(path, func, *args):
|
||||
try:
|
||||
return func(*args)
|
||||
except FileNotFoundError as err:
|
||||
# chmod() won't fix a missing file.
|
||||
if verbose >= 2:
|
||||
print('%s: %s' % (err.__class__.__name__, err))
|
||||
raise
|
||||
except OSError as err:
|
||||
if verbose >= 2:
|
||||
print('%s: %s' % (err.__class__.__name__, err))
|
||||
|
|
|
@ -109,7 +109,9 @@ class TestSpecifics(unittest.TestCase):
|
|||
self.assertEqual(d['z'], 12)
|
||||
|
||||
def test_extended_arg(self):
|
||||
longexpr = 'x = x or ' + '-x' * 2500
|
||||
# default: 1000 * 2.5 = 2500 repetitions
|
||||
repeat = int(sys.getrecursionlimit() * 2.5)
|
||||
longexpr = 'x = x or ' + '-x' * repeat
|
||||
g = {}
|
||||
code = '''
|
||||
def f(x):
|
||||
|
|
|
@ -9,7 +9,9 @@ from array import array
|
|||
from weakref import proxy
|
||||
from functools import wraps
|
||||
|
||||
from test.support import cpython_only, swap_attr, gc_collect, is_emscripten
|
||||
from test.support import (
|
||||
cpython_only, swap_attr, gc_collect, is_emscripten, is_wasi
|
||||
)
|
||||
from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd)
|
||||
from test.support.warnings_helper import check_warnings
|
||||
from collections import UserList
|
||||
|
@ -65,6 +67,7 @@ class AutoFileTests:
|
|||
self.assertRaises((AttributeError, TypeError),
|
||||
setattr, f, attr, 'oops')
|
||||
|
||||
@unittest.skipIf(is_wasi, "WASI does not expose st_blksize.")
|
||||
def testBlksize(self):
|
||||
# test private _blksize attribute
|
||||
blksize = io.DEFAULT_BUFFER_SIZE
|
||||
|
|
|
@ -156,6 +156,8 @@ class TestFileMethods(LargeFileTest):
|
|||
def skip_no_disk_space(path, required):
|
||||
def decorator(fun):
|
||||
def wrapper(*args, **kwargs):
|
||||
if not hasattr(shutil, "disk_usage"):
|
||||
raise unittest.SkipTest("requires shutil.disk_usage")
|
||||
if shutil.disk_usage(os.path.realpath(path)).free < required:
|
||||
hsize = int(required / 1024 / 1024)
|
||||
raise unittest.SkipTest(
|
||||
|
|
|
@ -5280,6 +5280,7 @@ class FileHandlerTest(BaseFileTest):
|
|||
self.assertEqual(fp.read().strip(), '1')
|
||||
|
||||
class RotatingFileHandlerTest(BaseFileTest):
|
||||
@unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.")
|
||||
def test_should_not_rollover(self):
|
||||
# If maxbytes is zero rollover never occurs
|
||||
rh = logging.handlers.RotatingFileHandler(
|
||||
|
@ -5387,6 +5388,7 @@ class RotatingFileHandlerTest(BaseFileTest):
|
|||
rh.close()
|
||||
|
||||
class TimedRotatingFileHandlerTest(BaseFileTest):
|
||||
@unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.")
|
||||
def test_should_not_rollover(self):
|
||||
# See bpo-45401. Should only ever rollover regular files
|
||||
fh = logging.handlers.TimedRotatingFileHandler(
|
||||
|
|
|
@ -11,7 +11,6 @@ import fnmatch
|
|||
import fractions
|
||||
import itertools
|
||||
import locale
|
||||
import mmap
|
||||
import os
|
||||
import pickle
|
||||
import select
|
||||
|
@ -59,6 +58,10 @@ try:
|
|||
except ImportError:
|
||||
INT_MAX = PY_SSIZE_T_MAX = sys.maxsize
|
||||
|
||||
try:
|
||||
import mmap
|
||||
except ImportError:
|
||||
mmap = None
|
||||
|
||||
from test.support.script_helper import assert_python_ok
|
||||
from test.support import unix_shell
|
||||
|
@ -2167,7 +2170,8 @@ class TestInvalidFD(unittest.TestCase):
|
|||
|
||||
@unittest.skipUnless(hasattr(os, 'fpathconf'), 'test needs os.fpathconf()')
|
||||
@unittest.skipIf(
|
||||
support.is_emscripten, "musl libc issue on Emscripten, bpo-46390"
|
||||
support.is_emscripten or support.is_wasi,
|
||||
"musl libc issue on Emscripten/WASI, bpo-46390"
|
||||
)
|
||||
def test_fpathconf(self):
|
||||
self.check(os.pathconf, "PC_NAME_MAX")
|
||||
|
@ -2460,6 +2464,7 @@ class Win32KillTests(unittest.TestCase):
|
|||
# os.kill on Windows can take an int which gets set as the exit code
|
||||
self._kill(100)
|
||||
|
||||
@unittest.skipIf(mmap is None, "requires mmap")
|
||||
def _kill_with_event(self, event, name):
|
||||
tagname = "test_os_%s" % uuid.uuid1()
|
||||
m = mmap.mmap(-1, 1, tagname)
|
||||
|
|
|
@ -107,6 +107,10 @@ class PosixTests(unittest.TestCase):
|
|||
script = os.path.join(dirname, 'signalinterproctester.py')
|
||||
assert_python_ok(script)
|
||||
|
||||
@unittest.skipUnless(
|
||||
hasattr(signal, "valid_signals"),
|
||||
"requires signal.valid_signals"
|
||||
)
|
||||
def test_valid_signals(self):
|
||||
s = signal.valid_signals()
|
||||
self.assertIsInstance(s, set)
|
||||
|
@ -212,6 +216,7 @@ class WakeupFDTests(unittest.TestCase):
|
|||
self.assertRaises((ValueError, OSError),
|
||||
signal.set_wakeup_fd, fd)
|
||||
|
||||
@unittest.skipUnless(support.has_socket_support, "needs working sockets.")
|
||||
def test_invalid_socket(self):
|
||||
sock = socket.socket()
|
||||
fd = sock.fileno()
|
||||
|
@ -241,6 +246,7 @@ class WakeupFDTests(unittest.TestCase):
|
|||
self.assertEqual(signal.set_wakeup_fd(-1), -1)
|
||||
|
||||
@unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.")
|
||||
@unittest.skipUnless(support.has_socket_support, "needs working sockets.")
|
||||
def test_set_wakeup_fd_socket_result(self):
|
||||
sock1 = socket.socket()
|
||||
self.addCleanup(sock1.close)
|
||||
|
|
|
@ -6,6 +6,7 @@ import copy
|
|||
import datetime
|
||||
from decimal import Decimal as D
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
|
@ -91,11 +92,13 @@ class TestMiscellaneous(unittest.TestCase):
|
|||
self.assertEqual(obj_copy, expected_obj)
|
||||
|
||||
def test_inline_array_recursion_limit(self):
|
||||
nest_count = 470
|
||||
# 470 with default recursion limit
|
||||
nest_count = int(sys.getrecursionlimit() * 0.47)
|
||||
recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]"
|
||||
tomllib.loads(recursive_array_toml)
|
||||
|
||||
def test_inline_table_recursion_limit(self):
|
||||
nest_count = 310
|
||||
# 310 with default recursion limit
|
||||
nest_count = int(sys.getrecursionlimit() * 0.31)
|
||||
recursive_table_toml = nest_count * "key = {" + nest_count * "}"
|
||||
tomllib.loads(recursive_table_toml)
|
||||
|
|
|
@ -804,6 +804,7 @@ class BadFileZipImportTestCase(unittest.TestCase):
|
|||
os_helper.create_empty_file(TESTMOD)
|
||||
self.assertZipFailure(TESTMOD)
|
||||
|
||||
@unittest.skipIf(support.is_wasi, "mode 000 not supported.")
|
||||
def testFileUnreadable(self):
|
||||
os_helper.unlink(TESTMOD)
|
||||
fd = os.open(TESTMOD, os.O_CREAT, 000)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Decrease default recursion limit on WASI to address limited call stack size.
|
|
@ -1481,7 +1481,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
|
|||
|
||||
#elif defined(HAVE_CLOCK_GETTIME) && \
|
||||
defined(CLOCK_PROCESS_CPUTIME_ID) && \
|
||||
!defined(__EMSCRIPTEN__)
|
||||
!defined(__EMSCRIPTEN__) && !defined(__wasi__)
|
||||
#define HAVE_THREAD_TIME
|
||||
|
||||
#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
# define D(x)
|
||||
#endif
|
||||
|
||||
# define MAXSTACK 6000
|
||||
#ifdef __wasi__
|
||||
# define MAXSTACK 4000
|
||||
#else
|
||||
# define MAXSTACK 6000
|
||||
#endif
|
||||
static const int n_keyword_lists = 9;
|
||||
static KeywordToken *reserved_keywords[] = {
|
||||
(KeywordToken[]) {{NULL, -1}},
|
||||
|
|
|
@ -37,7 +37,11 @@ EXTENSION_PREFIX = """\
|
|||
# define D(x)
|
||||
#endif
|
||||
|
||||
# define MAXSTACK 6000
|
||||
#ifdef __wasi__
|
||||
# define MAXSTACK 4000
|
||||
#else
|
||||
# define MAXSTACK 6000
|
||||
#endif
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
@ -220,10 +220,27 @@ AddType application/wasm wasm
|
|||
|
||||
# WASI (wasm32-wasi)
|
||||
|
||||
WASI builds require [WASI SDK](https://github.com/WebAssembly/wasi-sdk) and
|
||||
currently [wasix](https://github.com/singlestore-labs/wasix) for POSIX
|
||||
WASI builds require [WASI SDK](https://github.com/WebAssembly/wasi-sdk) 15.0+
|
||||
and currently [wasix](https://github.com/singlestore-labs/wasix) for POSIX
|
||||
compatibility stubs.
|
||||
|
||||
## WASI limitations and issues (WASI SDK 15.0)
|
||||
|
||||
A lot of Emscripten limitations also apply to WASI. Noticable restrictions
|
||||
are:
|
||||
|
||||
- Call stack size is limited. Default recursion limit and parser stack size
|
||||
are smaller than in regular Python builds.
|
||||
- ``socket(2)`` cannot create new socket file descriptors. WASI programs can
|
||||
call read/write/accept on a file descriptor that is passed into the process.
|
||||
- ``socket.gethostname()`` and host name resolution APIs like
|
||||
``socket.gethostbyname()`` are not implemented and always fail.
|
||||
- ``chmod(2)`` is not available. It's not possible to modify file permissions,
|
||||
yet. A future version of WASI may provide a limited ``set_permissions`` API.
|
||||
- File locking (``fcntl``) is not available.
|
||||
- ``os.pipe()``, ``os.mkfifo()``, and ``os.mknod()`` are not supported.
|
||||
|
||||
|
||||
# Detect WebAssembly builds
|
||||
|
||||
## Python code
|
||||
|
|
|
@ -17,3 +17,24 @@ ac_cv_header_sys_resource_h=no
|
|||
|
||||
# undefined symbols / unsupported features
|
||||
ac_cv_func_eventfd=no
|
||||
|
||||
# WASI SDK 15.0 has no pipe syscall.
|
||||
ac_cv_func_pipe=no
|
||||
|
||||
# WASI SDK 15.0 cannot create fifos and special files.
|
||||
ac_cv_func_mkfifo=no
|
||||
ac_cv_func_mkfifoat=no
|
||||
ac_cv_func_mknod=no
|
||||
ac_cv_func_mknodat=no
|
||||
|
||||
# fdopendir() fails on SDK 15.0,
|
||||
# OSError: [Errno 28] Invalid argument: '.'
|
||||
ac_cv_func_fdopendir=no
|
||||
|
||||
# WASIX stubs we don't want to use.
|
||||
ac_cv_func_kill=no
|
||||
|
||||
# WASI sockets are limited to operations on given socket fd and inet sockets.
|
||||
# Disable AF_UNIX and AF_PACKET support, see socketmodule.h.
|
||||
ac_cv_header_sys_un_h=no
|
||||
ac_cv_header_netpacket_packet_h=no
|
||||
|
|
|
@ -22611,6 +22611,7 @@ case $ac_sys_system in #(
|
|||
|
||||
|
||||
py_cv_module__ctypes_test=n/a
|
||||
py_cv_module_fcntl=n/a
|
||||
py_cv_module_=n/a
|
||||
|
||||
|
||||
|
|
|
@ -6690,8 +6690,10 @@ AS_CASE([$ac_sys_system],
|
|||
],
|
||||
[Emscripten/node*], [],
|
||||
[WASI/*], [
|
||||
dnl WASI SDK 15.0 does not support file locking.
|
||||
PY_STDLIB_MOD_SET_NA(
|
||||
[_ctypes_test],
|
||||
[fcntl],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue