diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c859ccb7..38fed6b14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ language runtime. The main focus is on user-observable behavior of the engine. * Add a new context option `python.UnicodeCharacterDatabaseNativeFallback` to control whether the ICU database may fall back to the native unicode character database from CPython for features and characters not supported by ICU. This requires native access to be enabled and is disabled by default for embeddings. * Add a new context option `python.AllowSignalHandlers` to control whether Python code may install signal handlers. This is disabled by default for Java embedding and enabled in the standalone. * Add an experimental `python.InitializationEntropySource` option to control the entropy source used for initialization-only randomness such as hash secret generation and `random.Random(None)` seeding. This means embeddings and tests can select deterministic or externally provided initialization entropy without affecting cryptographically relevant APIs like `os.urandom()` or `random.SystemRandom()`. +* Dispatch `sys.audit` events to hooks registered with `sys.addaudithook`, including audit events raised through the `PySys_Audit` C API. * Foreign temporal objects (dates, times, and timezones) are now given a Python class corresponding to their interop traits, i.e., `date`, `time`, `datetime`, or `tzinfo`. This allows any foreign objects with these traits to be used in place of the native Python types and Python methods available on these types work on the foreign types. * Make BouncyCastle an optional dependency for embedding use cases. BouncyCastle is only needed for legacy RSA, DSA, and EC privat keys versions 0 and 1. To support these from Python embeddings, BouncyCastle must now be explicitly enabled by adding the `org.graalvm.python:python-bouncycastle-support` Maven artifact. * The GraalPy Native standalone on Linux now uses a lower-footprint Native Image garbage collection configuration. This reduces resident set size (RSS) for many workloads, but may increase startup time and warmup time, and can slow down some workloads. diff --git a/graalpython/com.oracle.graal.python.cext/src/sysmodule.c b/graalpython/com.oracle.graal.python.cext/src/sysmodule.c index 79b28f3aaa..9c7df408ea 100644 --- a/graalpython/com.oracle.graal.python.cext/src/sysmodule.c +++ b/graalpython/com.oracle.graal.python.cext/src/sysmodule.c @@ -44,8 +44,32 @@ #include "pycore_pystate.h" // _PyThreadState_GET() int PySys_Audit(const char *event, const char *argFormat, ...) { - // ignore for now - return 0; + PyObject *args; + if (argFormat == NULL) { + args = PyTuple_New(0); + if (args == NULL) { + return -1; + } + } else { + va_list va; + va_start(va, argFormat); + args = Py_VaBuildValue(argFormat, va); + va_end(va); + if (args == NULL) { + return -1; + } + if (!PyTuple_Check(args)) { + PyObject *tmp = PyTuple_Pack(1, args); + Py_DECREF(args); + if (tmp == NULL) { + return -1; + } + args = tmp; + } + } + int result = GraalPyPrivate_Sys_Audit(event, args); + Py_DECREF(args); + return result; } static void diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_sys.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_sys.py index ea5c0d2b95..cebff02cf5 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_sys.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_sys.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -39,7 +39,12 @@ import sys -from . import CPyExtTestCase, CPyExtFunction, unhandled_error_compare +from . import ( + CPyExtFunction, + CPyExtTestCase, + compile_module_from_string, + unhandled_error_compare, +) def _reference_get_object(args): @@ -49,7 +54,76 @@ def _reference_get_object(args): raise SystemError # raised by PyBuildValue(..., NULL) class TestPySys(CPyExtTestCase): - + def test_PySys_Audit(self): + module = compile_module_from_string(""" + #define PY_SSIZE_T_CLEAN + #include + + static PyObject* audit(PyObject* self, PyObject* Py_UNUSED(args)) { + PyObject *value = PyUnicode_FromString("value"); + if (value == NULL) { + return NULL; + } + int res = PySys_Audit("graalpy.test_capi_audit", "Oi", value, 23); + Py_DECREF(value); + if (res < 0) { + return NULL; + } + return PyLong_FromLong(res); + } + + static PyObject* audit_error(PyObject* self, PyObject* Py_UNUSED(args)) { + PyObject *value = PyUnicode_FromString("value"); + if (value == NULL) { + return NULL; + } + int res = PySys_Audit("graalpy.test_capi_audit_error", "O", value); + Py_DECREF(value); + if (res < 0) { + return NULL; + } + return PyLong_FromLong(res); + } + + static PyMethodDef methods[] = { + {"audit", audit, METH_NOARGS, NULL}, + {"audit_error", audit_error, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} + }; + + static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, "test_sys_audit", NULL, -1, methods + }; + + PyMODINIT_FUNC PyInit_test_sys_audit(void) { + return PyModule_Create(&module); + } + """, "test_sys_audit") + + seen = [] + + def hook(event, args): + if event == "graalpy.test_capi_audit": + seen.append(args) + + sys.addaudithook(hook) + + self.assertEqual(module.audit(), 0) + self.assertEqual(seen, [("value", 23)]) + + class AuditError(Exception): + pass + + def error_hook(event, args): + if event == "graalpy.test_capi_audit_error": + raise AuditError(args) + + sys.addaudithook(error_hook) + + with self.assertRaises(AuditError) as cm: + module.audit_error() + self.assertEqual(cm.exception.args[0], ("value",)) + test_PySys_GetObject = CPyExtFunction( _reference_get_object, lambda: ( diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_audit_hooks.py b/graalpython/com.oracle.graal.python.test/src/tests/test_audit_hooks.py new file mode 100644 index 0000000000..e941dc779c --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_audit_hooks.py @@ -0,0 +1,129 @@ +# Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import sys +import tempfile +import unittest + + +class AuditHookTests(unittest.TestCase): + def test_sys_audit_calls_registered_hook(self): + seen = [] + + def hook(event, args): + if event == "graalpy.test_sys_audit": + seen.append((event, args)) + + sys.addaudithook(hook) + sys.audit("graalpy.test_sys_audit", 1, "two") + + self.assertEqual(seen, [("graalpy.test_sys_audit", (1, "two"))]) + + def test_sys_audit_propagates_hook_exception(self): + class AuditError(Exception): + pass + + def hook(event, args): + if event == "graalpy.test_sys_audit_error": + raise AuditError(args) + + sys.addaudithook(hook) + + with self.assertRaises(AuditError): + sys.audit("graalpy.test_sys_audit_error", 42) + + def test_java_audit_site_calls_registered_hook(self): + seen = [] + + def hook(event, args): + if event == "open": + seen.append(args) + + sys.addaudithook(hook) + with tempfile.TemporaryFile("w"): + pass + + self.assertTrue(seen) + + def test_addaudithook_exception_blocks_new_hook(self): + seen = [] + block_add = True + + def blocking_hook(event, args): + nonlocal block_add + if event == "sys.addaudithook": + if not block_add: + return + block_add = False + raise RuntimeError("blocked") + if event == "graalpy.test_blocked_hook": + seen.append("blocking") + + def blocked_hook(event, args): + if event == "graalpy.test_blocked_hook": + seen.append("blocked") + + sys.addaudithook(blocking_hook) + sys.addaudithook(blocked_hook) + sys.audit("graalpy.test_blocked_hook") + + self.assertEqual(seen, ["blocking"]) + + def test_addaudithook_propagates_baseexception(self): + class AuditBaseException(BaseException): + pass + + block_add = True + + def hook(event, args): + nonlocal block_add + if event == "sys.addaudithook": + if not block_add: + return + block_add = False + raise AuditBaseException + + sys.addaudithook(hook) + + with self.assertRaises(AuditBaseException): + sys.addaudithook(lambda event, args: None) + + +if __name__ == "__main__": + unittest.main() diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_audit.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_audit.txt new file mode 100644 index 0000000000..06943432a2 --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_audit.txt @@ -0,0 +1,6 @@ +test.test_audit.AuditTest.test_basic @ linux-x86_64 +test.test_audit.AuditTest.test_block_add_hook @ linux-x86_64 +test.test_audit.AuditTest.test_block_add_hook_baseexception @ linux-x86_64 +test.test_audit.AuditTest.test_mmap @ linux-x86_64 +test.test_audit.AuditTest.test_socket @ linux-x86_64 +test.test_audit.AuditTest.test_sqlite3 @ linux-x86_64 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java index ff2d357fca..6c287f845f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java @@ -2427,6 +2427,7 @@ static Object doGeneric(VirtualFrame frame, Object arg, @Builtin(name = "input", minNumOfPositionalArgs = 0, parameterNames = {"prompt"}) @GenerateNodeFactory abstract static class InputNode extends PythonUnaryBuiltinNode { + private static final TruffleString T_BUILTINS_INPUT = tsLiteral("builtins.input"); @Specialization static Object input(VirtualFrame frame, Object prompt, @@ -2459,7 +2460,7 @@ private static Object doInput(Object prompt, Node node, PythonContext context) { throw PRaiseNode.raiseStatic(node, RuntimeError, ErrorMessages.INPUT_LOST_SYS_S, T_STDERR); } - SysModuleBuiltins.AuditNode.auditUncached("builtins.input", prompt != NO_VALUE ? prompt : NONE); + SysModuleBuiltins.AuditNode.auditUncached(T_BUILTINS_INPUT, prompt != NO_VALUE ? prompt : NONE); try { PyObjectCallMethodObjArgs.executeUncached(stderr, T_FLUSH); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java index 549d41c089..dc42e3f9ce 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/FcntlModuleBuiltins.java @@ -48,6 +48,7 @@ import static com.oracle.graal.python.runtime.PosixConstants.LOCK_NB; import static com.oracle.graal.python.runtime.PosixConstants.LOCK_SH; import static com.oracle.graal.python.runtime.PosixConstants.LOCK_UN; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import java.util.List; @@ -94,6 +95,9 @@ @CoreFunctions(defineModule = "fcntl") public final class FcntlModuleBuiltins extends PythonBuiltins { + private static final TruffleString T_FCNTL_FLOCK = tsLiteral("fcntl.flock"); + private static final TruffleString T_FCNTL_LOCKF = tsLiteral("fcntl.lockf"); + private static final TruffleString T_FCNT_IOCTL = tsLiteral("fcnt.ioctl"); @Override protected List> getNodeFactories() { @@ -131,7 +135,7 @@ synchronized PNone flock(VirtualFrame frame, int fd, int operation, @Cached SysModuleBuiltins.AuditNode auditNode, @CachedLibrary("getPosixSupport()") PosixSupportLibrary posix, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "fcntl.flock", fd, operation); + auditNode.audit(frame, inliningTarget, T_FCNTL_FLOCK, fd, operation); try { posix.flock(getPosixSupport(), fd, operation); } catch (PosixException e) { @@ -155,7 +159,7 @@ PNone lockf(VirtualFrame frame, int fd, int code, Object lenObj, Object startObj @Cached PyLongAsLongNode asLongNode, @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "fcntl.lockf", fd, code, lenObj != PNone.NO_VALUE ? lenObj : PNone.NONE, startObj != PNone.NO_VALUE ? startObj : PNone.NONE, whence); + auditNode.audit(frame, inliningTarget, T_FCNTL_LOCKF, fd, code, lenObj != PNone.NO_VALUE ? lenObj : PNone.NONE, startObj != PNone.NO_VALUE ? startObj : PNone.NONE, whence); int lockType; if (code == LOCK_UN.value) { lockType = F_UNLCK.getValueIfDefined(); @@ -212,7 +216,7 @@ Object ioctl(VirtualFrame frame, int fd, long request, Object arg, boolean mutat @Cached PRaiseNode raiseNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached SysModuleBuiltins.AuditNode auditNode) { - auditNode.audit(inliningTarget, "fcnt.ioctl", fd, request, arg); + auditNode.audit(frame, inliningTarget, T_FCNT_IOCTL, fd, request, arg); int intArg = 0; if (arg != PNone.NO_VALUE) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java index c83eff63c6..4ef96d0031 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MsvcrtModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,6 +40,8 @@ */ package com.oracle.graal.python.builtins.modules; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + import java.util.List; import com.oracle.graal.python.annotations.ArgumentClinic; @@ -62,6 +64,7 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.strings.TruffleString; @CoreFunctions(defineModule = "msvcrt", os = PythonOS.PLATFORM_WIN32) public final class MsvcrtModuleBuiltins extends PythonBuiltins { @@ -69,6 +72,7 @@ public final class MsvcrtModuleBuiltins extends PythonBuiltins { public static final int LK_LOCK = 1; public static final int LK_NBLCK = 2; public static final int LK_UNLOCK = 3; + private static final TruffleString T_MSVCRT_LOCKING = tsLiteral("msvcrt.locking"); @Override protected List> getNodeFactories() { @@ -95,7 +99,7 @@ Object locking(VirtualFrame frame, int fd, int mode, long nbytes, @Cached SysModuleBuiltins.AuditNode auditNode, @CachedLibrary("getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "msvcrt.locking", fd, mode, nbytes); + auditNode.audit(frame, inliningTarget, T_MSVCRT_LOCKING, fd, mode, nbytes); try { posixLib.fcntlLock(getPosixSupport(), fd, mode == LK_NBLCK, mode == LK_LOCK ? 1 : 0, 0, 0, nbytes); } catch (PosixSupportLibrary.PosixException e) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index 46fa0cb39d..650b0c0431 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -27,6 +27,7 @@ import static com.oracle.graal.python.nodes.BuiltinNames.T_ENVIRON; import static com.oracle.graal.python.nodes.BuiltinNames.T_NT; +import static com.oracle.graal.python.nodes.BuiltinNames.T_OPEN; import static com.oracle.graal.python.nodes.BuiltinNames.T_POSIX; import static com.oracle.graal.python.nodes.StringLiterals.T_DOT; import static com.oracle.graal.python.runtime.PosixConstants.AT_FDCWD; @@ -157,6 +158,23 @@ @CoreFunctions(defineModule = "posix", extendsModule = "nt", isEager = true) public final class PosixModuleBuiltins extends PythonBuiltins { + private static final TruffleString T_OS_PUTENV = tsLiteral("os.putenv"); + private static final TruffleString T_OS_UNSETENV = tsLiteral("os.unsetenv"); + private static final TruffleString T_OS_EXEC = tsLiteral("os.exec"); + private static final TruffleString T_OS_TRUNCATE = tsLiteral("os.truncate"); + private static final TruffleString T_OS_REMOVE = tsLiteral("os.remove"); + private static final TruffleString T_OS_MKDIR = tsLiteral("os.mkdir"); + private static final TruffleString T_OS_RMDIR = tsLiteral("os.rmdir"); + private static final TruffleString T_OS_SCANDIR = tsLiteral("os.scandir"); + private static final TruffleString T_OS_LISTDIR = tsLiteral("os.listdir"); + private static final TruffleString T_OS_UTIME = tsLiteral("os.utime"); + private static final TruffleString T_OS_RENAME = tsLiteral("os.rename"); + private static final TruffleString T_OS_CHMOD = tsLiteral("os.chmod"); + private static final TruffleString T_OS_CHOWN = tsLiteral("os.chown"); + private static final TruffleString T_OS_SYSTEM = tsLiteral("os.system"); + private static final TruffleString T_KILL = tsLiteral("kill"); + private static final TruffleString T_KILLPG = tsLiteral("killpg"); + static final StructSequence.BuiltinTypeDescriptor STAT_RESULT_DESC = new StructSequence.BuiltinTypeDescriptor( PythonBuiltinClassType.PStatResult, 10, @@ -412,7 +430,7 @@ static PNone putenv(VirtualFrame frame, PBytes nameBytes, PBytes valueBytes, Object nameOpaque = checkNull(inliningTarget, posixLib.createPathFromBytes(posixSupport, name), raiseNode); Object valueOpaque = checkNull(inliningTarget, posixLib.createPathFromBytes(posixSupport, value), raiseNode); checkEqualSign(inliningTarget, name, raiseNode); - auditNode.audit(inliningTarget, "os.putenv", nameBytes, valueBytes); + auditNode.audit(frame, inliningTarget, T_OS_PUTENV, nameBytes, valueBytes); try { posixLib.setenv(posixSupport, nameOpaque, valueOpaque, true); } catch (PosixException e) { @@ -458,7 +476,7 @@ static PNone putenv(VirtualFrame frame, PBytes nameBytes, @Cached PRaiseNode raiseNode) { byte[] name = toBytesNode.execute(nameBytes); Object nameOpaque = checkNull(inliningTarget, posixLib.createPathFromBytes(context.getPosixSupport(), name), raiseNode); - auditNode.audit(inliningTarget, "os.unsetenv", nameBytes); + auditNode.audit(frame, inliningTarget, T_OS_UNSETENV, nameBytes); try { posixLib.unsetenv(context.getPosixSupport(), nameOpaque); } catch (PosixException e) { @@ -542,7 +560,7 @@ private static void execv(VirtualFrame frame, PosixPath path, Object argv, Seque } // TODO ValueError "execv() arg 2 first element cannot be empty" - auditNode.audit(inliningTarget, "os.exec", path.originalObject, argv, PNone.NONE); + auditNode.audit(frame, inliningTarget, T_OS_EXEC, path.originalObject, argv, PNone.NONE); gil.release(true); try { @@ -851,7 +869,7 @@ static int open(VirtualFrame frame, PosixPath path, int flags, int mode, int dir if (O_CLOEXEC.defined) { fixedFlags |= O_CLOEXEC.getValueIfDefined(); } - auditNode.audit(inliningTarget, "open", path.originalObject, PNone.NONE, fixedFlags); + auditNode.audit(frame, inliningTarget, T_OPEN, path.originalObject, PNone.NONE, fixedFlags); gil.release(true); try { while (true) { @@ -1216,7 +1234,7 @@ static PNone ftruncate(VirtualFrame frame, int fd, long length, @Cached GilNode gil, @Cached InlinedBranchProfile errorProfile, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.truncate", fd, length); + auditNode.audit(frame, inliningTarget, T_OS_TRUNCATE, fd, length); while (true) { try { gil.release(true); @@ -1257,7 +1275,7 @@ static PNone truncate(VirtualFrame frame, PosixPath path, long length, @Exclusive @Cached SysModuleBuiltins.AuditNode auditNode, @Exclusive @Cached GilNode gil, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.truncate", path.originalObject, length); + auditNode.audit(frame, inliningTarget, T_OS_TRUNCATE, path.originalObject, length); try { gil.release(true); try { @@ -1620,7 +1638,7 @@ static PNone unlink(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.remove", path.originalObject, dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_REMOVE, path.originalObject, dirFdForAudit(dirFd)); try { posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, false); } catch (PosixException e) { @@ -1721,7 +1739,7 @@ static PNone mkdir(VirtualFrame frame, PosixPath path, int mode, int dirFd, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.mkdir", path.originalObject, mode, dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_MKDIR, path.originalObject, mode, dirFdForAudit(dirFd)); try { posixLib.mkdirat(context.getPosixSupport(), dirFd, path.value, mode); } catch (PosixException e) { @@ -1749,7 +1767,7 @@ static PNone rmdir(VirtualFrame frame, PosixPath path, int dirFd, @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.rmdir", path.originalObject, dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_RMDIR, path.originalObject, dirFdForAudit(dirFd)); try { posixLib.unlinkat(context.getPosixSupport(), dirFd, path.value, true); } catch (PosixException e) { @@ -1907,7 +1925,7 @@ static PScandirIterator scandirPath(VirtualFrame frame, PosixPath path, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.scandir", path.originalObject == null ? PNone.NONE : path.originalObject); + auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, posixLib.opendir(context.getPosixSupport(), path.value), path, false); } catch (PosixException e) { @@ -1922,7 +1940,7 @@ static PScandirIterator scandirFd(VirtualFrame frame, PosixFd fd, @Bind Node inliningTarget, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.scandir", fd.originalObject); + auditNode.audit(frame, inliningTarget, T_OS_SCANDIR, fd.originalObject); Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); return PFactory.createScandirIterator(context.getLanguage(inliningTarget), context, dirStream, fd, true); } @@ -1945,7 +1963,7 @@ static PList listdirPath(VirtualFrame frame, PosixPath path, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.listdir", path.originalObject == null ? PNone.NONE : path.originalObject); + auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, path.originalObject == null ? PNone.NONE : path.originalObject); try { return listdir(frame, inliningTarget, posixLib.opendir(context.getPosixSupport(), path.value), path.wasBufferLike, false, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); @@ -1961,7 +1979,7 @@ static PList listdirFd(VirtualFrame frame, PosixFd fd, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached SysModuleBuiltins.AuditNode auditNode, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.listdir", fd.originalObject); + auditNode.audit(frame, inliningTarget, T_OS_LISTDIR, fd.originalObject); Object dirStream = dupAndFdopendir(frame, inliningTarget, posixLib, context.getPosixSupport(), fd, constructAndRaiseNode); return listdir(frame, inliningTarget, dirStream, false, true, posixLib, constructAndRaiseNode, context.getLanguage(inliningTarget), context.getPosixSupport()); } @@ -2127,7 +2145,7 @@ static PNone utimensat(VirtualFrame frame, PosixPath path, Object times, Object @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); - auditNode.audit(inliningTarget, "os.utime", path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { posixLib.utimensat(context.getPosixSupport(), dirFd, path.value, timespec, followSymlinks); } catch (PosixException e) { @@ -2146,7 +2164,7 @@ static PNone utimes(VirtualFrame frame, PosixPath path, Object times, Object ns, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); - auditNode.audit(inliningTarget, "os.utime", path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { posixLib.utimes(context.getPosixSupport(), path.value, timeval); } catch (PosixException e) { @@ -2165,7 +2183,7 @@ static PNone lutimes(VirtualFrame frame, PosixPath path, Object times, Object ns @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); - auditNode.audit(inliningTarget, "os.utime", path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_UTIME, path.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { posixLib.lutimes(context.getPosixSupport(), path.value, timeval); } catch (PosixException e) { @@ -2198,7 +2216,7 @@ static PNone futimens(VirtualFrame frame, PosixFd fd, Object times, Object ns, i @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { long[] timespec = timespecNode.execute(frame, times, ns); - auditNode.audit(inliningTarget, "os.utime", fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { posixLib.futimens(context.getPosixSupport(), fd.fd, timespec); } catch (PosixException e) { @@ -2217,7 +2235,7 @@ static PNone futimes(VirtualFrame frame, PosixFd fd, Object times, Object ns, in @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { Timeval[] timeval = timespecNode.toTimeval(frame, times, ns); - auditNode.audit(inliningTarget, "os.utime", fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_UTIME, fd.originalObject, checkNone(times), checkNone(ns), dirFdForAudit(dirFd)); try { posixLib.futimes(context.getPosixSupport(), fd.fd, timeval); } catch (PosixException e) { @@ -2266,7 +2284,7 @@ static PNone rename(VirtualFrame frame, PosixPath src, PosixPath dst, int srcDir @Bind Node inliningTarget, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.rename", src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); + auditNode.audit(frame, inliningTarget, T_OS_RENAME, src.originalObject, dst.originalObject, dirFdForAudit(srcDirFd), dirFdForAudit(dstDirFd)); try { posixLib.renameat(context.getPosixSupport(), srcDirFd, src.value, dstDirFd, dst.value); } catch (PosixException e) { @@ -2338,7 +2356,7 @@ static PNone fchmod(VirtualFrame frame, int fd, int mode, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.chmod", fd, mode, -1); + auditNode.audit(frame, inliningTarget, T_OS_CHMOD, fd, mode, -1); try { posixLib.fchmod(context.getPosixSupport(), fd, mode); } catch (PosixException e) { @@ -2369,7 +2387,7 @@ static PNone chmodFollow(VirtualFrame frame, PosixPath path, int mode, int dirFd @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Shared @Cached PRaiseNode raiseNode) { - auditNode.audit(inliningTarget, "os.chmod", path.originalObject, mode, dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_CHMOD, path.originalObject, mode, dirFdForAudit(dirFd)); try { posixLib.fchmodat(context.getPosixSupport(), dirFd, path.value, mode, followSymlinks); } catch (PosixException e) { @@ -2395,7 +2413,7 @@ static PNone chmodFollow(VirtualFrame frame, PosixFd fd, int mode, int dirFd, @S @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @SuppressWarnings("unused") @Shared @Cached PRaiseNode raiseNode) { - auditNode.audit(inliningTarget, "os.chmod", fd.originalObject, mode, dirFdForAudit(dirFd)); + auditNode.audit(frame, inliningTarget, T_OS_CHMOD, fd.originalObject, mode, dirFdForAudit(dirFd)); // Unlike stat and utime which raise CANT_SPECIFY_DIRFD_WITHOUT_PATH or // CANNOT_USE_FD_AND_FOLLOW_SYMLINKS_TOGETHER when an inappropriate combination of // arguments is used, CPython's implementation of chmod simply ignores dir_fd and @@ -2423,7 +2441,7 @@ static Object chown(VirtualFrame frame, int fd, long uid, long gid, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.chown", fd, uid, gid, -1); + auditNode.audit(frame, inliningTarget, T_OS_CHOWN, fd, uid, gid, -1); try { gil.release(true); try { @@ -2457,7 +2475,7 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "os.chown", path.originalObject, uid, gid, -1); + auditNode.audit(frame, inliningTarget, T_OS_CHOWN, path.originalObject, uid, gid, -1); try { gil.release(true); try { @@ -2495,7 +2513,7 @@ static Object chown(VirtualFrame frame, PosixPath path, long uid, long gid, int @Shared @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, // unused node to avoid mixing shared and non-shared inlined nodes @Shared @Cached PRaiseNode raiseNode) { - auditNode.audit(inliningTarget, "os.chown", path.originalObject, uid, gid, dirFd != AT_FDCWD.value ? dirFd : -1); + auditNode.audit(frame, inliningTarget, T_OS_CHOWN, path.originalObject, uid, gid, dirFd != AT_FDCWD.value ? dirFd : -1); try { gil.release(true); try { @@ -2524,7 +2542,7 @@ static Object chown(VirtualFrame frame, PosixFd fd, long uid, long gid, int dirF if (followSymlinks) { throw raiseNode.raise(inliningTarget, ValueError, ErrorMessages.CANNOT_USE_FD_AND_FOLLOW_SYMLINKS_TOGETHER, "chown"); } - auditNode.audit(inliningTarget, "os.chown", fd.originalObject, uid, gid, -1); + auditNode.audit(frame, inliningTarget, T_OS_CHOWN, fd.originalObject, uid, gid, -1); try { gil.release(true); try { @@ -2854,7 +2872,7 @@ protected ArgumentClinicProvider getArgumentClinic() { } @Specialization - static int system(PBytes command, + static int system(VirtualFrame frame, PBytes command, @Bind Node inliningTarget, @Cached BytesNodes.ToBytesNode toBytesNode, @Cached SysModuleBuiltins.AuditNode auditNode, @@ -2864,7 +2882,7 @@ static int system(PBytes command, // Unlike in other posix builtins, we go through str -> bytes -> byte[] -> String // conversions for emulated backend because the bytes version after fsencode conversion // is subject to sys.audit. - auditNode.audit(inliningTarget, "os.system", command); + auditNode.audit(frame, inliningTarget, T_OS_SYSTEM, command); byte[] bytes = toBytesNode.execute(command); gil.release(true); try { @@ -3014,7 +3032,7 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "kill", pid, signal); + auditNode.audit(frame, inliningTarget, T_KILL, pid, signal); try { posixLib.kill(context.getPosixSupport(), pid, signal); return PNone.NONE; @@ -3041,7 +3059,7 @@ static PNone kill(VirtualFrame frame, long pid, int signal, @Bind PythonContext context, @CachedLibrary("context.getPosixSupport()") PosixSupportLibrary posixLib, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "killpg", pid, signal); + auditNode.audit(frame, inliningTarget, T_KILLPG, pid, signal); try { posixLib.killpg(context.getPosixSupport(), pid, signal); return PNone.NONE; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java index bc8e0d3a94..c2a3bdf724 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SocketModuleBuiltins.java @@ -138,6 +138,13 @@ @CoreFunctions(defineModule = J__SOCKET) public final class SocketModuleBuiltins extends PythonBuiltins { + private static final TruffleString T_SOCKET_GETHOSTNAME = tsLiteral("socket.gethostname"); + private static final TruffleString T_SOCKET_GETHOSTBYADDR = tsLiteral("socket.gethostbyaddr"); + private static final TruffleString T_SOCKET_GETHOSTBYNAME = tsLiteral("socket.gethostbyname"); + private static final TruffleString T_SOCKET_GETSERVBYNAME = tsLiteral("socket.getservbyname"); + private static final TruffleString T_SOCKET_GETSERVBYPORT = tsLiteral("socket.getservbyport"); + private static final TruffleString T_SOCKET_GETNAMEINFO = tsLiteral("socket.getnameinfo"); + private static final TruffleString T_SOCKET_GETADDRINFO = tsLiteral("socket.getaddrinfo"); @Override protected List> getNodeFactories() { @@ -239,7 +246,7 @@ static TruffleString doGeneric(VirtualFrame frame, @Cached SysModuleBuiltins.AuditNode auditNode, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { - auditNode.audit(inliningTarget, "socket.gethostname"); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTNAME); try { gil.release(true); try { @@ -274,7 +281,7 @@ static Object doGeneric(VirtualFrame frame, Object ip, * TODO this uses getnameinfo and getaddrinfo to emulate the legacy gethostbyaddr. We * might want to use the legacy API in the future */ - auditNode.audit(inliningTarget, "socket.gethostbyaddr", ip); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYADDR, ip); UniversalSockAddr addr = setIpAddrNode.execute(frame, idnaConverter.execute(frame, ip), AF_UNSPEC.value); int family = sockAddrLibrary.getFamily(addr); try { @@ -333,7 +340,7 @@ static TruffleString getHostByName(VirtualFrame frame, Object nameObj, @Cached SocketNodes.SetIpAddrNode setIpAddrNode, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); - auditNode.audit(inliningTarget, "socket.gethostbyname", PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYNAME, PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); UniversalSockAddr addr = setIpAddrNode.execute(frame, name, AF_INET.value); Inet4SockAddr inet4SockAddr = addrLib.asInet4SockAddr(addr); try { @@ -364,7 +371,7 @@ static Object get(VirtualFrame frame, Object nameObj, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { byte[] name = idnaConverter.execute(frame, nameObj); // The event name is really without the _ex, it's not a copy-paste error - auditNode.audit(inliningTarget, "socket.gethostbyname", PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETHOSTBYNAME, PFactory.createTuple(context.getLanguage(inliningTarget), new Object[]{nameObj})); /* * TODO this uses getaddrinfo to emulate the legacy gethostbyname. It doesn't support * aliases and multiple addresses. We might want to use the legacy gethostbyname_r API @@ -405,7 +412,7 @@ protected static IdnaFromStringOrBytesConverterNode createIdnaConverter() { @GenerateNodeFactory public abstract static class GetServByNameNode extends PythonBinaryClinicBuiltinNode { @Specialization - static Object getServByName(TruffleString serviceName, Object protocolNameObj, + static Object getServByName(VirtualFrame frame, TruffleString serviceName, Object protocolNameObj, @Bind Node inliningTarget, @Cached InlinedConditionProfile noneProtocol, @Bind PythonContext context, @@ -429,7 +436,7 @@ static Object getServByName(TruffleString serviceName, Object protocolNameObj, * TODO this uses getaddrinfo to emulate the legacy getservbyname. We might want to use * the legacy API in the future */ - auditNode.audit(inliningTarget, "socket.getservbyname", serviceName, protocolName != null ? protocolName : ""); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETSERVBYNAME, serviceName, protocolName != null ? protocolName : T_EMPTY_STRING); int protocol = 0; if (protocolName != null) { @@ -454,7 +461,7 @@ static Object getServByName(TruffleString serviceName, Object protocolNameObj, } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); } catch (PosixException e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); + throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -473,7 +480,7 @@ public abstract static class GetServByPortNode extends PythonBinaryClinicBuiltin public static final TruffleString T_UDP = tsLiteral("udp"); @Specialization - Object getServByPort(int port, Object protocolNameObj, + Object getServByPort(VirtualFrame frame, int port, Object protocolNameObj, @Bind Node inliningTarget, @Cached InlinedConditionProfile nonProtocol, @CachedLibrary(limit = "1") PosixSupportLibrary posixLib, @@ -497,7 +504,7 @@ Object getServByPort(int port, Object protocolNameObj, if (port < 0 || port > 0xffff) { throw raiseNode.raise(inliningTarget, OverflowError, ErrorMessages.S_PORT_RANGE, "getservbyport"); } - auditNode.audit(inliningTarget, "socket.getservbyport", port, protocolName != null ? protocolName : ""); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETSERVBYPORT, port, protocolName != null ? protocolName : T_EMPTY_STRING); try { gil.release(true); @@ -517,7 +524,7 @@ Object getServByPort(int port, Object protocolNameObj, } catch (GetAddrInfoException e) { throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.SERVICE_PROTO_NOT_FOUND); } catch (PosixException e) { - throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(null, e); + throw constructAndRaiseNode.get(inliningTarget).raiseOSErrorFromPosixException(frame, e); } } @@ -577,7 +584,7 @@ static Object getNameInfo(VirtualFrame frame, PTuple sockaddr, int flags, scopeid = asIntNode.execute(frame, inliningTarget, getItem.execute(inliningTarget, addr, 3)); } - auditNode.audit(inliningTarget, "socket.getnameinfo", sockaddr); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETNAMEINFO, sockaddr); try { UniversalSockAddr resolvedAddr; @@ -683,7 +690,7 @@ static Object getAddrInfo(VirtualFrame frame, Object hostObject, Object portObje throw raiseNode.raise(inliningTarget, OSError, ErrorMessages.INT_OR_STRING_EXPECTED); } - auditNode.audit(inliningTarget, "socket.getaddrinfo", hostObject, portObjectProfiled, family, type, proto, flags); + auditNode.audit(frame, inliningTarget, T_SOCKET_GETADDRINFO, hostObject, portObjectProfiled, family, type, proto, flags); AddrInfoCursor cursor; try { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java index bf48f57400..721966021d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SysModuleBuiltins.java @@ -244,6 +244,7 @@ import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode; import com.oracle.graal.python.runtime.CallerFlags; @@ -898,6 +899,7 @@ static PFrame counted(VirtualFrame frame, int depth, @GenerateNodeFactory abstract static class CurrentFrames extends PythonBuiltinNode { private static final long CURRENT_FRAMES_TIMEOUT_MILLIS = 20; + private static final TruffleString T_SYS_CURRENT_FRAMES = tsLiteral("sys._current_frames"); @Specialization Object currentFrames(VirtualFrame frame, @@ -909,7 +911,7 @@ Object currentFrames(VirtualFrame frame, @Cached ObjectHashMap.PutNode putNode, @Bind PythonContext context, @Bind PythonLanguage language) { - auditNode.audit(inliningTarget, "sys._current_frames"); + auditNode.audit(frame, inliningTarget, T_SYS_CURRENT_FRAMES); PFrame currentFrame = readFrameNode.getCurrentPythonFrame(frame); EconomicMapStorage framesMap = collectCurrentFrames(inliningTarget, context, currentFrame); return PFactory.createDict(language, framesMap); @@ -1123,31 +1125,32 @@ protected static LookupAndCallUnaryNode createWithoutError() { } } - // TODO implement support for audit events @GenerateUncached @GenerateInline @GenerateCached(false) public abstract static class AuditNode extends Node { - protected abstract void executeInternal(Node inliningTarget, Object event, Object[] arguments); + protected abstract void executeInternal(VirtualFrame frame, Node inliningTarget, TruffleString event, Object[] arguments); - public void audit(Node inliningTarget, String event, Object... arguments) { - executeInternal(inliningTarget, event, arguments); + public static void auditUncached(TruffleString event, Object... arguments) { + SysModuleBuiltinsFactory.AuditNodeGen.getUncached().executeInternal(null, null, event, arguments); } - public static void auditUncached(String event, Object... arguments) { - SysModuleBuiltinsFactory.AuditNodeGen.getUncached().executeInternal(null, event, arguments); - } - - public void audit(Node inliningTarget, TruffleString event, Object... arguments) { - executeInternal(inliningTarget, event, arguments); - } - - @Specialization - void doAudit(@SuppressWarnings("unused") TruffleString event, @SuppressWarnings("unused") Object[] arguments) { + public void audit(VirtualFrame frame, Node inliningTarget, TruffleString event, Object... arguments) { + executeInternal(frame, inliningTarget, event, arguments); } @Specialization - void doAudit(@SuppressWarnings("unused") String event, @SuppressWarnings("unused") Object[] arguments) { + static void doAudit(VirtualFrame frame, Node inliningTarget, TruffleString event, Object[] arguments, + @Bind PythonContext context, + @Bind PythonLanguage language, + @Cached CallNode.Lazy callNode) { + Object[] hooks = context.getAuditHooks(); + if (hooks.length > 0) { + PTuple argsTuple = PFactory.createTuple(language, arguments); + for (Object hook : hooks) { + callNode.get(inliningTarget).execute(frame, hook, event, argsTuple); + } + } } } @@ -1157,9 +1160,18 @@ void doAudit(@SuppressWarnings("unused") String event, @SuppressWarnings("unused @GenerateNodeFactory abstract static class SysAuditNode extends PythonBuiltinNode { @Specialization - @SuppressWarnings("unused") - Object doAudit(VirtualFrame frame, Object event, Object[] args) { - // TODO: Stub audit hooks implementation for PEP 578 + static Object doAudit(VirtualFrame frame, Object event, Object[] args, + @Bind Node inliningTarget, + @Cached CastToTruffleStringNode castEventNode, + @Cached AuditNode auditNode, + @Cached PRaiseNode raiseNode) { + final TruffleString eventString; + try { + eventString = castEventNode.execute(inliningTarget, event); + } catch (CannotCastException e) { + throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.S_ARG_1_MUST_BE_STR_NOT_P, "audit", event); + } + auditNode.audit(frame, inliningTarget, eventString, args); return PNone.NONE; } } @@ -1170,10 +1182,21 @@ Object doAudit(VirtualFrame frame, Object event, Object[] args) { "Adds a new audit hook callback.") @GenerateNodeFactory abstract static class SysAuditHookNode extends PythonBuiltinNode { + private static final TruffleString T_SYS_ADDAUDITHOOK = tsLiteral("sys.addaudithook"); + @Specialization - @SuppressWarnings("unused") - Object doAudit(VirtualFrame frame, Object hook) { - // TODO: Stub audit hooks implementation for PEP 578 + static Object doAudit(VirtualFrame frame, Object hook, + @Bind Node inliningTarget, + @Bind PythonContext context, + @Cached AuditNode auditNode, + @Cached IsBuiltinObjectProfile exceptionProfile) { + try { + auditNode.audit(frame, inliningTarget, T_SYS_ADDAUDITHOOK); + } catch (PException pe) { + pe.expect(inliningTarget, PythonBuiltinClassType.Exception, exceptionProfile); + return PNone.NONE; + } + context.addAuditHook(hook); return PNone.NONE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java index 5caf912fb1..8f40f49c60 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextSysBuiltins.java @@ -63,6 +63,7 @@ import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs; import com.oracle.graal.python.lib.PyObjectLookupAttr; import com.oracle.graal.python.lib.PyObjectSetAttr; +import com.oracle.graal.python.nodes.call.CallNode; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.truffle.api.CompilerAsserts; @@ -134,4 +135,15 @@ public static int GraalPyPrivate_Sys_PyFileWriteUnicode(int fd, long unicodePtr) PyObjectCallMethodObjArgs.executeUncached(selectOut(fd), T_WRITE, msg); return 0; } + + @CApiBuiltin(ret = Int, args = {ConstCharPtr, PyObject}, call = Ignored, acquireGil = false) + @TruffleBoundary + public static int GraalPyPrivate_Sys_Audit(long eventPtr, long argsPtr) { + TruffleString event = FromCharPointerNode.executeUncached(eventPtr); + Object args = NativeToPythonInternalNode.executeUncached(argsPtr, false); + for (Object hook : PythonContext.get(null).getAuditHooks()) { + CallNode.executeUncached(hook, event, args); + } + return 0; + } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java index 786be247d1..b308aaf531 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/FileIOBuiltins.java @@ -74,7 +74,7 @@ import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.createOutputStream; import static com.oracle.graal.python.builtins.objects.bytes.BytesUtils.toByteArray; import static com.oracle.graal.python.builtins.objects.exception.OSErrorEnum.EAGAIN; -import static com.oracle.graal.python.nodes.BuiltinNames.J_OPEN; +import static com.oracle.graal.python.nodes.BuiltinNames.T_OPEN; import static com.oracle.graal.python.nodes.ErrorMessages.BAD_MODE; import static com.oracle.graal.python.nodes.ErrorMessages.CANNOT_USE_CLOSEFD; import static com.oracle.graal.python.nodes.ErrorMessages.EMBEDDED_NULL_BYTE; @@ -176,7 +176,6 @@ @CoreFunctions(extendClasses = PythonBuiltinClassType.PFileIO) public final class FileIOBuiltins extends PythonBuiltins { - /* * We are limited to max primitive array size, Integer.MAX_VALUE, the jdk can offer. CPython * defines the max value as system's SSIZE_T_MAX on linux and INT_MAX for MacOS and Windows. @@ -362,7 +361,7 @@ static void doInit(VirtualFrame frame, Node inliningTarget, PFileIO self, Object } int flags = processMode(self, mode); - auditNode.audit(inliningTarget, J_OPEN, nameobj, mode.mode, flags); + auditNode.audit(frame, inliningTarget, T_OPEN, nameobj, mode.mode, flags); try { boolean fdIsOwn = false; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java index a0c127f9c3..19baa772dd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/mmap/MMapBuiltins.java @@ -156,6 +156,7 @@ @CoreFunctions(extendClasses = PythonBuiltinClassType.PMMap) public final class MMapBuiltins extends PythonBuiltins { public static final TpSlots SLOTS = MMapBuiltinsSlotsGen.SLOTS; + private static final TruffleString T_MMAP_NEW = tsLiteral("mmap.__new__"); @Override protected List> getNodeFactories() { @@ -243,7 +244,7 @@ static PMMap doFile(VirtualFrame frame, Object clazz, int fd, long lengthIn, int throw raiseNode.raise(inliningTarget, PythonBuiltinClassType.ValueError, ErrorMessages.MEM_MAPPED_OFFSET_INVALID_ACCESS); } - auditNode.audit(inliningTarget, "mmap.__new__", fd, lengthIn, access, offset); + auditNode.audit(frame, inliningTarget, T_MMAP_NEW, fd, lengthIn, access, offset); // For file mappings we use fstat to validate the length or to initialize the length if // it is 0 meaning that we should find it out for the user diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java index 8549653c93..e80d199a7b 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java @@ -55,6 +55,7 @@ import static com.oracle.graal.python.runtime.PosixConstants.SO_ERROR; import static com.oracle.graal.python.runtime.PosixConstants.SO_PROTOCOL; import static com.oracle.graal.python.runtime.PosixConstants.SO_TYPE; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import java.util.List; @@ -126,6 +127,10 @@ public final class SocketBuiltins extends PythonBuiltins { public static final TpSlots SLOTS = SocketBuiltinsSlotsGen.SLOTS; + private static final TruffleString T_SOCKET_NEW = tsLiteral("socket.__new__"); + private static final TruffleString T_SOCKET_BIND = tsLiteral("socket.bind"); + private static final TruffleString T_SOCKET_CONNECT = tsLiteral("socket.connect"); + private static final TruffleString T_SOCKET_SENDTO = tsLiteral("socket.sendto"); @Override protected List> getNodeFactories() { @@ -173,7 +178,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i @Cached GilNode gil, @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { // sic! CPython really has __new__ there, even though it's in __init__ - auditNode.audit(inliningTarget, "socket.__new__", self, familyIn, typeIn, protoIn); + auditNode.audit(frame, inliningTarget, T_SOCKET_NEW, self, familyIn, typeIn, protoIn); int family = familyIn; if (family == -1) { family = PosixConstants.AF_INET.value; @@ -225,7 +230,7 @@ static Object init(VirtualFrame frame, PSocket self, int familyIn, int typeIn, i @Exclusive @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode, @Cached PRaiseNode raiseNode) { // sic! CPython really has __new__ there, even though it's in __init__ - auditNode.audit(inliningTarget, "socket.__new__", self, familyIn, typeIn, protoIn); + auditNode.audit(frame, inliningTarget, T_SOCKET_NEW, self, familyIn, typeIn, protoIn); int fd = asIntNode.execute(frame, inliningTarget, fileno); if (fd < 0) { @@ -353,7 +358,7 @@ static Object bind(VirtualFrame frame, PSocket self, Object address, @Cached GilNode gil, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { UniversalSockAddr addr = getSockAddrArgNode.execute(frame, self, address, "bind"); - auditNode.audit(inliningTarget, "socket.bind", self, address); + auditNode.audit(frame, inliningTarget, T_SOCKET_BIND, self, address); try { gil.release(true); @@ -416,7 +421,7 @@ static Object connect(VirtualFrame frame, PSocket self, Object address, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { UniversalSockAddr connectAddr = getSockAddrArgNode.execute(frame, self, address, "connect"); - auditNode.audit(inliningTarget, "socket.connect", self, address); + auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); try { doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); @@ -477,7 +482,7 @@ static Object connectEx(VirtualFrame frame, PSocket self, Object address, @Cached PConstructAndRaiseNode.Lazy constructAndRaiseNode) { UniversalSockAddr connectAddr = getSockAddrArgNode.execute(frame, self, address, "connect_ex"); - auditNode.audit(inliningTarget, "socket.connect", self, address); // sic! connect + auditNode.audit(frame, inliningTarget, T_SOCKET_CONNECT, self, address); // sic! connect try { ConnectNode.doConnect(frame, inliningTarget, constructAndRaiseNode, posixLib, context.getPosixSupport(), gil, self, connectAddr); @@ -976,7 +981,7 @@ static Object sendTo(VirtualFrame frame, PSocket socket, Object bufferObj, Objec checkSelectable(inliningTarget, raiseNode, socket); UniversalSockAddr addr = getSockAddrArgNode.execute(frame, socket, address, "sendto"); - auditNode.audit(inliningTarget, "socket.sendto", socket, address); + auditNode.audit(frame, inliningTarget, T_SOCKET_SENDTO, socket, address); int len = bufferLib.getBufferLength(buffer); byte[] bytes = bufferLib.getInternalOrCopiedByteArray(buffer); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java index d4e830e3e8..fb9ba2261d 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TypeBuiltins.java @@ -73,6 +73,7 @@ import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; import java.util.Arrays; import java.util.List; @@ -189,6 +190,7 @@ @CoreFunctions(extendClasses = PythonBuiltinClassType.PythonClass) public final class TypeBuiltins extends PythonBuiltins { public static final TpSlots SLOTS = TypeBuiltinsSlotsGen.SLOTS; + private static final TruffleString T_OBJECT_SETATTR = tsLiteral("object.__setattr__"); @Override protected List> getNodeFactories() { @@ -868,10 +870,10 @@ abstract static class AbstractSlotNode extends PythonBinaryBuiltinNode { @GenerateInline @GenerateCached(false) abstract static class CheckSetSpecialTypeAttrNode extends Node { - abstract void execute(Node inliningTarget, Object type, Object value, TruffleString name); + abstract void execute(VirtualFrame frame, Node inliningTarget, Object type, Object value, TruffleString name); @Specialization - static void check(Node inliningTarget, Object type, Object value, TruffleString name, + static void check(VirtualFrame frame, Node inliningTarget, Object type, Object value, TruffleString name, @Cached PRaiseNode raiseNode, @Cached(inline = false) GetTypeFlagsNode getTypeFlagsNode, @Cached SysModuleBuiltins.AuditNode auditNode) { @@ -882,7 +884,7 @@ static void check(Node inliningTarget, Object type, Object value, TruffleString // Sic, it's not immutable, but CPython has this message throw raiseNode.raise(inliningTarget, TypeError, ErrorMessages.CANT_DELETE_ATTRIBUTE_S_OF_IMMUTABLE_TYPE_N, name, type); } - auditNode.audit(inliningTarget, "object.__setattr__", type, name, value); + auditNode.audit(frame, inliningTarget, T_OBJECT_SETATTR, type, name, value); } } @@ -935,7 +937,7 @@ static Object setName(VirtualFrame frame, Object cls, Object value, @Cached TruffleString.IndexOfCodePointNode indexOfCodePointNode, @Cached SetNameInnerNode innerNode, @Cached PRaiseNode raiseNode) { - check.execute(inliningTarget, cls, value, T___NAME__); + check.execute(frame, inliningTarget, cls, value, T___NAME__); TruffleString string; try { string = castToTruffleStringNode.execute(inliningTarget, value); @@ -1088,13 +1090,13 @@ static void set(PythonAbstractNativeObject type, TruffleString value, } @Specialization(guards = "!isNoValue(value)") - static Object setName(Object cls, Object value, + static Object setName(VirtualFrame frame, Object cls, Object value, @Bind Node inliningTarget, @Cached CheckSetSpecialTypeAttrNode check, @Cached CastToTruffleStringNode castToStringNode, @Cached SetQualNameInnerNode innerNode, @Cached PRaiseNode raiseNode) { - check.execute(inliningTarget, cls, value, T___QUALNAME__); + check.execute(frame, inliningTarget, cls, value, T___QUALNAME__); TruffleString stringValue; try { stringValue = castToStringNode.execute(inliningTarget, value); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java index 70c6b83296..9720d86aea 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/BuiltinNames.java @@ -207,6 +207,7 @@ private static TruffleString tsLiteral(String s) { public static final TruffleString T_INT = tsLiteral(J_INT); public static final String J_OPEN = "open"; + public static final TruffleString T_OPEN = tsLiteral(J_OPEN); public static final String J_STR = "str"; public static final TruffleString T_STR = tsLiteral(J_STR); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java index a552dc7362..b7b2f5c680 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/PythonContext.java @@ -760,6 +760,7 @@ static PythonThreadState getThreadState(Node n) { private PythonModule mainModule; private final List shutdownHooks = new ArrayList<>(); private final List atExitHooks = new ArrayList<>(); + private final List auditHooks = new ArrayList<>(); private final List capiHooks = new ArrayList<>(); private final HashMap nativeClassStableAssumptions = new HashMap<>(); private final ThreadGroup threadGroup = new ThreadGroup(GRAALPYTHON_THREADS); @@ -2144,6 +2145,16 @@ public void clearAtexitHooks() { atExitHooks.clear(); } + @TruffleBoundary + public Object[] getAuditHooks() { + return auditHooks.toArray(PythonUtils.EMPTY_OBJECT_ARRAY); + } + + @TruffleBoundary + public void addAuditHook(Object hook) { + auditHooks.add(hook); + } + public void registerCApiHook(Runnable hook) { if (getCApiState() == CApiState.INITIALIZED) { hook.run();