summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2019-05-23 15:45:22 (GMT)
committerGitHub <noreply@github.com>2019-05-23 15:45:22 (GMT)
commitb82e17e626f7b1cd98aada0b1ebb65cb9f8fb184 (patch)
tree5370a2a075707cb0b37ce135cad6ffe23da424c4 /Objects
parente788057a9188ff37e232729815dfda2529079420 (diff)
downloadcpython-b82e17e626f7b1cd98aada0b1ebb65cb9f8fb184.zip
cpython-b82e17e626f7b1cd98aada0b1ebb65cb9f8fb184.tar.gz
cpython-b82e17e626f7b1cd98aada0b1ebb65cb9f8fb184.tar.bz2
bpo-36842: Implement PEP 578 (GH-12613)
Adds sys.audit, sys.addaudithook, io.open_code, and associated C APIs.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/codeobject.c6
-rw-r--r--Objects/descrobject.c8
-rw-r--r--Objects/fileobject.c70
-rw-r--r--Objects/funcobject.c40
-rw-r--r--Objects/object.c8
-rw-r--r--Objects/typeobject.c11
6 files changed, 142 insertions, 1 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 62d7c5d..f4e48a9 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -380,6 +380,12 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
&PyTuple_Type, &cellvars))
return NULL;
+ if (PySys_Audit("code.__new__", "OOOiiiii",
+ code, filename, name, argcount, kwonlyargcount,
+ nlocals, stacksize, flags) < 0) {
+ goto cleanup;
+ }
+
if (argcount < 0) {
PyErr_SetString(
PyExc_ValueError,
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 8f1a823..0db8057 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -144,6 +144,14 @@ member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type)
if (descr_check((PyDescrObject *)descr, obj, &res))
return res;
+
+ if (descr->d_member->flags & READ_RESTRICTED) {
+ if (PySys_Audit("object.__getattr__", "Os",
+ obj ? obj : Py_None, descr->d_member->name) < 0) {
+ return NULL;
+ }
+ }
+
return PyMember_GetOne((char *)obj, descr->d_member);
}
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 39c7c10..3b02633 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -2,6 +2,7 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
+#include "pycore_pystate.h"
#if defined(HAVE_GETC_UNLOCKED) && !defined(_Py_MEMORY_SANITIZER)
/* clang MemorySanitizer doesn't yet understand getc_unlocked. */
@@ -33,7 +34,8 @@ PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const c
PyObject *io, *stream;
_Py_IDENTIFIER(open);
- io = PyImport_ImportModule("io");
+ /* import _io in case we are being used to open io.py */
+ io = PyImport_ImportModule("_io");
if (io == NULL)
return NULL;
stream = _PyObject_CallMethodId(io, &PyId_open, "isisssi", fd, mode,
@@ -514,6 +516,72 @@ PyTypeObject PyStdPrinter_Type = {
};
+/* ************************** open_code hook ***************************
+ * The open_code hook allows embedders to override the method used to
+ * open files that are going to be used by the runtime to execute code
+ */
+
+int
+PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook, void *userData) {
+ if (Py_IsInitialized() &&
+ PySys_Audit("setopencodehook", NULL) < 0) {
+ return -1;
+ }
+
+ if (_PyRuntime.open_code_hook) {
+ if (Py_IsInitialized()) {
+ PyErr_SetString(PyExc_SystemError,
+ "failed to change existing open_code hook");
+ }
+ return -1;
+ }
+
+ _PyRuntime.open_code_hook = hook;
+ _PyRuntime.open_code_userdata = userData;
+ return 0;
+}
+
+PyObject *
+PyFile_OpenCodeObject(PyObject *path)
+{
+ PyObject *iomod, *f = NULL;
+ _Py_IDENTIFIER(open);
+
+ if (!PyUnicode_Check(path)) {
+ PyErr_Format(PyExc_TypeError, "'path' must be 'str', not '%.200s'",
+ Py_TYPE(path)->tp_name);
+ return NULL;
+ }
+
+ Py_OpenCodeHookFunction hook = _PyRuntime.open_code_hook;
+ if (hook) {
+ f = hook(path, _PyRuntime.open_code_userdata);
+ } else {
+ iomod = PyImport_ImportModule("_io");
+ if (iomod) {
+ f = _PyObject_CallMethodId(iomod, &PyId_open, "Os",
+ path, "rb");
+ Py_DECREF(iomod);
+ }
+ }
+
+ return f;
+}
+
+PyObject *
+PyFile_OpenCode(const char *utf8path)
+{
+ PyObject *pathobj = PyUnicode_FromString(utf8path);
+ PyObject *f;
+ if (!pathobj) {
+ return NULL;
+ }
+ f = PyFile_OpenCodeObject(pathobj);
+ Py_DECREF(pathobj);
+ return f;
+}
+
+
#ifdef __cplusplus
}
#endif
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index e8e2d2e..09b94c2 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -250,6 +250,10 @@ static PyMemberDef func_memberlist[] = {
static PyObject *
func_get_code(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
+ if (PySys_Audit("object.__getattr__", "Os", op, "__code__") < 0) {
+ return NULL;
+ }
+
Py_INCREF(op->func_code);
return op->func_code;
}
@@ -266,6 +270,12 @@ func_set_code(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored))
"__code__ must be set to a code object");
return -1;
}
+
+ if (PySys_Audit("object.__setattr__", "OsO",
+ op, "__code__", value) < 0) {
+ return -1;
+ }
+
nfree = PyCode_GetNumFree((PyCodeObject *)value);
nclosure = (op->func_closure == NULL ? 0 :
PyTuple_GET_SIZE(op->func_closure));
@@ -329,6 +339,9 @@ func_set_qualname(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
static PyObject *
func_get_defaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
+ if (PySys_Audit("object.__getattr__", "Os", op, "__defaults__") < 0) {
+ return NULL;
+ }
if (op->func_defaults == NULL) {
Py_RETURN_NONE;
}
@@ -348,6 +361,16 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
"__defaults__ must be set to a tuple object");
return -1;
}
+ if (value) {
+ if (PySys_Audit("object.__setattr__", "OsO",
+ op, "__defaults__", value) < 0) {
+ return -1;
+ }
+ } else if (PySys_Audit("object.__delattr__", "Os",
+ op, "__defaults__") < 0) {
+ return -1;
+ }
+
Py_XINCREF(value);
Py_XSETREF(op->func_defaults, value);
return 0;
@@ -356,6 +379,10 @@ func_set_defaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignored
static PyObject *
func_get_kwdefaults(PyFunctionObject *op, void *Py_UNUSED(ignored))
{
+ if (PySys_Audit("object.__getattr__", "Os",
+ op, "__kwdefaults__") < 0) {
+ return NULL;
+ }
if (op->func_kwdefaults == NULL) {
Py_RETURN_NONE;
}
@@ -375,6 +402,16 @@ func_set_kwdefaults(PyFunctionObject *op, PyObject *value, void *Py_UNUSED(ignor
"__kwdefaults__ must be set to a dict object");
return -1;
}
+ if (value) {
+ if (PySys_Audit("object.__setattr__", "OsO",
+ op, "__kwdefaults__", value) < 0) {
+ return -1;
+ }
+ } else if (PySys_Audit("object.__delattr__", "Os",
+ op, "__kwdefaults__") < 0) {
+ return -1;
+ }
+
Py_XINCREF(value);
Py_XSETREF(op->func_kwdefaults, value);
return 0;
@@ -507,6 +544,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
}
}
}
+ if (PySys_Audit("function.__new__", "O", code) < 0) {
+ return NULL;
+ }
newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code,
globals);
diff --git a/Objects/object.c b/Objects/object.c
index 604f5e0..f842ab3 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1366,6 +1366,14 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
}
+ /* XXX [Steve Dower] These are really noisy - worth it? */
+ /*if (PyType_Check(obj) || PyModule_Check(obj)) {
+ if (value && PySys_Audit("object.__setattr__", "OOO", obj, name, value) < 0)
+ return -1;
+ if (!value && PySys_Audit("object.__delattr__", "OO", obj, name) < 0)
+ return -1;
+ }*/
+
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c086f18..49b45b8 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -392,6 +392,12 @@ check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *nam
"can't delete %s.%s", type->tp_name, name);
return 0;
}
+
+ if (PySys_Audit("object.__setattr__", "OsO",
+ type, name, value) < 0) {
+ return 0;
+ }
+
return 1;
}
@@ -3956,6 +3962,11 @@ object_set_class(PyObject *self, PyObject *value, void *closure)
Py_TYPE(value)->tp_name);
return -1;
}
+ if (PySys_Audit("object.__setattr__", "OsO",
+ self, "__class__", value) < 0) {
+ return -1;
+ }
+
newto = (PyTypeObject *)value;
/* In versions of CPython prior to 3.5, the code in
compatible_for_assignment was not set up to correctly check for memory