summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_ceval.h8
-rwxr-xr-xLib/platform.py4
-rw-r--r--Lib/test/pythoninfo.py10
-rw-r--r--Lib/test/support/__init__.py5
-rw-r--r--Lib/test/test_compile.py4
-rw-r--r--Lib/test/test_fileio.py5
-rw-r--r--Lib/test/test_largefile.py2
-rw-r--r--Lib/test/test_logging.py2
-rw-r--r--Lib/test/test_os.py9
-rw-r--r--Lib/test/test_signal.py6
-rw-r--r--Lib/test/test_tomllib/test_misc.py7
-rw-r--r--Lib/test/test_zipimport.py1
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst1
-rw-r--r--Modules/timemodule.c2
-rw-r--r--Parser/parser.c6
-rw-r--r--Tools/peg_generator/pegen/c_generator.py6
-rw-r--r--Tools/wasm/README.md21
-rw-r--r--Tools/wasm/config.site-wasm32-wasi21
-rwxr-xr-xconfigure1
-rw-r--r--configure.ac2
20 files changed, 109 insertions, 14 deletions
diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h
index 8dd89c6..3efd6be 100644
--- a/Include/internal/pycore_ceval.h
+++ b/Include/internal/pycore_ceval.h
@@ -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
diff --git a/Lib/platform.py b/Lib/platform.py
index 3f3f25a..c272c40 100755
--- a/Lib/platform.py
+++ b/Lib/platform.py
@@ -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
diff --git a/Lib/test/pythoninfo.py b/Lib/test/pythoninfo.py
index 28549a6..84e1c04 100644
--- a/Lib/test/pythoninfo.py
+++ b/Lib/test/pythoninfo.py
@@ -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):
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index e4bda94..c284fc6 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -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))
diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 487a4fa..d435724 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -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):
diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py
index e4984d3..c26cdc02 100644
--- a/Lib/test/test_fileio.py
+++ b/Lib/test/test_fileio.py
@@ -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
diff --git a/Lib/test/test_largefile.py b/Lib/test/test_largefile.py
index 8f6bec1..3c11c59 100644
--- a/Lib/test/test_largefile.py
+++ b/Lib/test/test_largefile.py
@@ -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(
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index e69afae..fd56232 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -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(
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 36ad587..ae07182 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -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)
diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py
index 6d3b299..6aa529b 100644
--- a/Lib/test/test_signal.py
+++ b/Lib/test/test_signal.py
@@ -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)
diff --git a/Lib/test/test_tomllib/test_misc.py b/Lib/test/test_tomllib/test_misc.py
index 76fa590..378db58 100644
--- a/Lib/test/test_tomllib/test_misc.py
+++ b/Lib/test/test_tomllib/test_misc.py
@@ -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)
diff --git a/Lib/test/test_zipimport.py b/Lib/test/test_zipimport.py
index 85dbf4d..6678926 100644
--- a/Lib/test/test_zipimport.py
+++ b/Lib/test/test_zipimport.py
@@ -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)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst
new file mode 100644
index 0000000..1f9f45a
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-15-15-25-05.gh-issue-90473.MoPHYW.rst
@@ -0,0 +1 @@
+Decrease default recursion limit on WASI to address limited call stack size.
diff --git a/Modules/timemodule.c b/Modules/timemodule.c
index 7475ef3..18f9ddb 100644
--- a/Modules/timemodule.c
+++ b/Modules/timemodule.c
@@ -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)
diff --git a/Parser/parser.c b/Parser/parser.c
index adc8d50..08bf6d2 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -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}},
diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py
index 56a1e5a..65bfd59 100644
--- a/Tools/peg_generator/pegen/c_generator.py
+++ b/Tools/peg_generator/pegen/c_generator.py
@@ -37,7 +37,11 @@ EXTENSION_PREFIX = """\
# define D(x)
#endif
-# define MAXSTACK 6000
+#ifdef __wasi__
+# define MAXSTACK 4000
+#else
+# define MAXSTACK 6000
+#endif
"""
diff --git a/Tools/wasm/README.md b/Tools/wasm/README.md
index 83806f0..977b2bb 100644
--- a/Tools/wasm/README.md
+++ b/Tools/wasm/README.md
@@ -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
diff --git a/Tools/wasm/config.site-wasm32-wasi b/Tools/wasm/config.site-wasm32-wasi
index 255e99c..ee3fc83 100644
--- a/Tools/wasm/config.site-wasm32-wasi
+++ b/Tools/wasm/config.site-wasm32-wasi
@@ -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
diff --git a/configure b/configure
index 0281088..6fa4051 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/configure.ac b/configure.ac
index eab3262..bef4904 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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],
)
]
)