bpo-36842: Implement PEP 578 (GH-12613)

Adds sys.audit, sys.addaudithook, io.open_code, and associated C APIs.
diff --git a/Include/cpython/fileobject.h b/Include/cpython/fileobject.h
new file mode 100644
index 0000000..57eac13
--- /dev/null
+++ b/Include/cpython/fileobject.h
@@ -0,0 +1,32 @@
+#ifndef Py_CPYTHON_FILEOBJECT_H
+#  error "this header file must not be included directly"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
+
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
+PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
+#endif
+
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
+PyAPI_DATA(int) Py_UTF8Mode;
+#endif
+
+/* The std printer acts as a preliminary sys.stderr until the new io
+   infrastructure is in place. */
+PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
+PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
+
+typedef PyObject * (*Py_OpenCodeHookFunction)(PyObject *, void *);
+
+PyAPI_FUNC(PyObject *) PyFile_OpenCode(const char *utf8path);
+PyAPI_FUNC(PyObject *) PyFile_OpenCodeObject(PyObject *path);
+PyAPI_FUNC(int) PyFile_SetOpenCodeHook(Py_OpenCodeHookFunction hook, void *userData);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Include/cpython/sysmodule.h b/Include/cpython/sysmodule.h
new file mode 100644
index 0000000..72d8ffe
--- /dev/null
+++ b/Include/cpython/sysmodule.h
@@ -0,0 +1,21 @@
+#ifndef Py_CPYTHON_SYSMODULE_H
+#  error "this header file must not be included directly"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key);
+PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *);
+
+PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
+
+typedef int(*Py_AuditHookFunction)(const char *, PyObject *, void *);
+
+PyAPI_FUNC(int) PySys_Audit(const char*, const char *, ...);
+PyAPI_FUNC(int) PySys_AddAuditHook(Py_AuditHookFunction, void*);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Include/fileobject.h b/Include/fileobject.h
index 89e8dd6..456887e 100644
--- a/Include/fileobject.h
+++ b/Include/fileobject.h
@@ -15,32 +15,13 @@
 PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);
 PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *);
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
-#endif
 
 /* The default encoding used by the platform file system APIs
    If non-NULL, this is different than the default encoding for strings
 */
 PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding;
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03060000
-PyAPI_DATA(const char *) Py_FileSystemDefaultEncodeErrors;
-#endif
 PyAPI_DATA(int) Py_HasFileSystemDefaultEncoding;
 
-#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03070000
-PyAPI_DATA(int) Py_UTF8Mode;
-#endif
-
-/* Internal API
-
-   The std printer acts as a preliminary sys.stderr until the new io
-   infrastructure is in place. */
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
-PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
-#endif /* Py_LIMITED_API */
-
 /* A routine to check if a file descriptor can be select()-ed. */
 #ifdef _MSC_VER
     /* On Windows, any socket fd can be select()-ed, no matter how high */
@@ -49,6 +30,12 @@
     #define _PyIsSelectable_fd(FD) ((unsigned int)(FD) < (unsigned int)FD_SETSIZE)
 #endif
 
+#ifndef Py_LIMITED_API
+#  define Py_CPYTHON_FILEOBJECT_H
+#  include  "cpython/fileobject.h"
+#  undef Py_CPYTHON_FILEOBJECT_H
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index 1561328..ef1d8a0 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -9,8 +9,10 @@
 #endif
 
 #include "cpython/coreconfig.h"
+#include "fileobject.h"
 #include "pystate.h"
 #include "pythread.h"
+#include "sysmodule.h"
 
 #include "pycore_gil.h"   /* _gil_runtime_state  */
 #include "pycore_pathconfig.h"
@@ -131,6 +133,8 @@
     uint64_t tstate_next_unique_id;
 
     struct _warnings_runtime_state warnings;
+
+    PyObject *audit_hooks;
 };
 
 PyAPI_FUNC(struct _is*) _PyInterpreterState_LookUpID(PY_INT64_T);
@@ -154,6 +158,13 @@
     struct _xidregitem *next;
 };
 
+/* runtime audit hook state */
+
+typedef struct _Py_AuditHookEntry {
+    struct _Py_AuditHookEntry *next;
+    Py_AuditHookFunction hookCFunction;
+    void *userData;
+} _Py_AuditHookEntry;
 
 /* GIL state */
 
@@ -224,6 +235,11 @@
     struct _gilstate_runtime_state gilstate;
 
     _PyPreConfig preconfig;
+
+    Py_OpenCodeHookFunction open_code_hook;
+    void *open_code_userdata;
+    _Py_AuditHookEntry *audit_hook_head;
+
     // XXX Consolidate globals found via the check-c-globals script.
 } _PyRuntimeState;
 
diff --git a/Include/pydtrace.d b/Include/pydtrace.d
index a6a5e7e..5e6a626 100644
--- a/Include/pydtrace.d
+++ b/Include/pydtrace.d
@@ -12,6 +12,7 @@
     probe gc__done(long);
     probe import__find__load__start(const char *);
     probe import__find__load__done(const char *, int);
+    probe audit(const char *, void *);
 };
 
 #pragma D attributes Evolving/Evolving/Common provider python provider
diff --git a/Include/pydtrace.h b/Include/pydtrace.h
index 7a04278..75f8e7f 100644
--- a/Include/pydtrace.h
+++ b/Include/pydtrace.h
@@ -36,6 +36,7 @@
 static inline void PyDTrace_INSTANCE_DELETE_DONE(int arg0) {}
 static inline void PyDTrace_IMPORT_FIND_LOAD_START(const char *arg0) {}
 static inline void PyDTrace_IMPORT_FIND_LOAD_DONE(const char *arg0, int arg1) {}
+static inline void PyDTrace_AUDIT(const char *arg0, void *arg1) {}
 
 static inline int PyDTrace_LINE_ENABLED(void) { return 0; }
 static inline int PyDTrace_FUNCTION_ENTRY_ENABLED(void) { return 0; }
@@ -48,6 +49,7 @@
 static inline int PyDTrace_INSTANCE_DELETE_DONE_ENABLED(void) { return 0; }
 static inline int PyDTrace_IMPORT_FIND_LOAD_START_ENABLED(void) { return 0; }
 static inline int PyDTrace_IMPORT_FIND_LOAD_DONE_ENABLED(void) { return 0; }
+static inline int PyDTrace_AUDIT_ENABLED(void) { return 0; }
 
 #endif /* !WITH_DTRACE */
 
diff --git a/Include/sysmodule.h b/Include/sysmodule.h
index c5547ff..670e5d2 100644
--- a/Include/sysmodule.h
+++ b/Include/sysmodule.h
@@ -9,10 +9,6 @@
 
 PyAPI_FUNC(PyObject *) PySys_GetObject(const char *);
 PyAPI_FUNC(int) PySys_SetObject(const char *, PyObject *);
-#ifndef Py_LIMITED_API
-PyAPI_FUNC(PyObject *) _PySys_GetObjectId(_Py_Identifier *key);
-PyAPI_FUNC(int) _PySys_SetObjectId(_Py_Identifier *key, PyObject *);
-#endif
 
 PyAPI_FUNC(void) PySys_SetArgv(int, wchar_t **);
 PyAPI_FUNC(void) PySys_SetArgvEx(int, wchar_t **, int);
@@ -34,7 +30,9 @@
 PyAPI_FUNC(PyObject *) PySys_GetXOptions(void);
 
 #ifndef Py_LIMITED_API
-PyAPI_FUNC(size_t) _PySys_GetSizeOf(PyObject *);
+#  define Py_CPYTHON_SYSMODULE_H
+#  include  "cpython/sysmodule.h"
+#  undef Py_CPYTHON_SYSMODULE_H
 #endif
 
 #ifdef __cplusplus