``ctypes.dlsym`` with arguments ``library`` (the library object) and ``name``
(the symbol's name as a string or integer).
+.. audit-event:: ctypes.dlsym/handle handle,name ctypes.LibraryLoader
+
+ In cases when only the library handle is available rather than the object,
+ accessing a function raises an auditing event ``ctypes.dlsym/handle`` with
+ arguments ``handle`` (the raw library handle) and ``name``.
+
.. _ctypes-foreign-functions:
Foreign functions
passed arguments.
+.. audit-event:: ctypes.seh_exception code foreign-functions
+
+ On Windows, when a foreign function call raises a system exception (for
+ example, due to an access violation), it will be captured and replaced with
+ a suitable Python exception. Further, an auditing event
+ ``ctypes.seh_exception`` with argument ``code`` will be raised, allowing an
+ audit hook to replace the exception with its own.
+
+.. audit-event:: ctypes.call_function func_pointer,arguments ctype-foreign-functions
+
+ Some ways to invoke foreign function calls may raise an auditing event
+ ``ctypes.call_function`` with arguments ``function pointer`` and ``arguments``.
+
.. _ctypes-function-prototypes:
Function prototypes
Returns the address of the memory buffer as integer. *obj* must be an
instance of a ctypes type.
+ .. audit-event:: ctypes.addressof obj ctypes.addressof
+
.. function:: alignment(obj_or_type)
termination character. An integer can be passed as second argument which allows
specifying the size of the array if the length of the bytes should not be used.
+ .. audit-event:: ctypes.create_string_buffer init,size ctypes.create_string_buffer
.. function:: create_unicode_buffer(init_or_size, size=None)
allows specifying the size of the array if the length of the string should not
be used.
+ .. audit-event:: ctypes.create_unicode_buffer init,size ctypes.create_unicode_buffer
.. function:: DllCanUnloadNow()
Returns the current value of the ctypes-private copy of the system
:data:`errno` variable in the calling thread.
+ .. audit-event:: ctypes.get_errno "" ctypes.get_errno
+
.. function:: get_last_error()
Windows only: returns the current value of the ctypes-private copy of the system
:data:`LastError` variable in the calling thread.
+ .. audit-event:: ctypes.get_last_error "" ctypes.get_last_error
+
.. function:: memmove(dst, src, count)
Same as the standard C memmove library function: copies *count* bytes from
Set the current value of the ctypes-private copy of the system :data:`errno`
variable in the calling thread to *value* and return the previous value.
+ .. audit-event:: ctypes.set_errno errno ctypes.set_errno
.. function:: set_last_error(value)
:data:`LastError` variable in the calling thread to *value* and return the
previous value.
+ .. audit-event:: ctypes.set_last_error error ctypes.set_last_error
.. function:: sizeof(obj_or_type)
object. If size is specified, it is used as size, otherwise the string is assumed
to be zero-terminated.
+ .. audit-event:: ctypes.string_at address,size ctypes.string_at
+
.. function:: WinError(code=None, descr=None)
characters of the string, otherwise the string is assumed to be
zero-terminated.
+ .. audit-event:: ctypes.wstring_at address,size ctypes.wstring_at
+
.. _ctypes-data-types:
source buffer in bytes; the default is zero. If the source buffer is not
large enough a :exc:`ValueError` is raised.
+ .. audit-event:: ctypes.cdata/buffer pointer,size,offset ctypes._CData.from_buffer
.. method:: _CData.from_buffer_copy(source[, offset])
is zero. If the source buffer is not large enough a :exc:`ValueError` is
raised.
+ .. audit-event:: ctypes.cdata/buffer pointer,size,offset ctypes._CData.from_buffer_copy
+
.. method:: from_address(address)
This method returns a ctypes type instance using the memory specified by
if isinstance(init, bytes):
if size is None:
size = len(init)+1
+ _sys.audit("ctypes.create_string_buffer", init, size)
buftype = c_char * size
buf = buftype()
buf.value = init
return buf
elif isinstance(init, int):
+ _sys.audit("ctypes.create_string_buffer", None, init)
buftype = c_char * init
buf = buftype()
return buf
# 32-bit wchar_t (1 wchar_t per Unicode character). +1 for
# trailing NUL character.
size = len(init) + 1
+ _sys.audit("ctypes.create_unicode_buffer", init, size)
buftype = c_wchar * size
buf = buftype()
buf.value = init
return buf
elif isinstance(init, int):
+ _sys.audit("ctypes.create_unicode_buffer", None, init)
buftype = c_wchar * init
buf = buftype()
return buf
--- /dev/null
+Add additional audit events for the :mod:`ctypes` module.
return NULL;
}
+ if (PySys_Audit("ctypes.cdata/buffer", "nnn",
+ (Py_ssize_t)buffer->buf, buffer->len, offset) < 0) {
+ Py_DECREF(mv);
+ return NULL;
+ }
+
result = PyCData_AtAddress(type, (char *)buffer->buf + offset);
if (result == NULL) {
Py_DECREF(mv);
return NULL;
}
+ if (PySys_Audit("ctypes.cdata/buffer", "nnn",
+ (Py_ssize_t)buffer.buf, buffer.len, offset) < 0) {
+ PyBuffer_Release(&buffer);
+ return NULL;
+ }
+
result = GenericPyCData_new((PyTypeObject *)type, NULL, NULL);
if (result != NULL) {
memcpy(((CDataObject *)result)->b_ptr,
if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name))
return NULL;
+ if (PySys_Audit("ctypes.dlsym", "O", args) < 0) {
+ return NULL;
+ }
obj = PyObject_GetAttrString(dll, "_handle");
if (!obj)
static PyObject *
string_at(const char *ptr, int size)
{
+ if (PySys_Audit("ctypes.string_at", "ni", (Py_ssize_t)ptr, size) < 0) {
+ return NULL;
+ }
if (size == -1)
return PyBytes_FromStringAndSize(ptr, strlen(ptr));
return PyBytes_FromStringAndSize(ptr, size);
wstring_at(const wchar_t *ptr, int size)
{
Py_ssize_t ssize = size;
+ if (PySys_Audit("ctypes.wstring_at", "nn", (Py_ssize_t)ptr, ssize) < 0) {
+ return NULL;
+ }
if (ssize == -1)
ssize = wcslen(ptr);
return PyUnicode_FromWideChar(ptr, ssize);
PyObject *errobj;
int *space;
- if (!PyArg_ParseTuple(args, "i", &new_errno))
+ if (!PyArg_ParseTuple(args, "i", &new_errno)) {
return NULL;
+ }
errobj = _ctypes_get_errobj(&space);
if (errobj == NULL)
return NULL;
static PyObject *
get_errno(PyObject *self, PyObject *args)
{
+ if (PySys_Audit("ctypes.get_errno", NULL) < 0) {
+ return NULL;
+ }
return get_error_internal(self, args, 0);
}
static PyObject *
set_errno(PyObject *self, PyObject *args)
{
+ if (PySys_Audit("ctypes.set_errno", "O", args) < 0) {
+ return NULL;
+ }
return set_error_internal(self, args, 0);
}
static PyObject *
get_last_error(PyObject *self, PyObject *args)
{
+ if (PySys_Audit("ctypes.get_last_error", NULL) < 0) {
+ return NULL;
+ }
return get_error_internal(self, args, 1);
}
static PyObject *
set_last_error(PyObject *self, PyObject *args)
{
+ if (PySys_Audit("ctypes.set_last_error", "O", args) < 0) {
+ return NULL;
+ }
return set_error_internal(self, args, 1);
}
#ifndef DONT_USE_SEH
static void SetException(DWORD code, EXCEPTION_RECORD *pr)
{
+ if (PySys_Audit("ctypes.seh_exception", "I", code) < 0) {
+ /* An exception was set by the audit hook */
+ return;
+ }
+
/* The 'code' is a normal win32 error code so it could be handled by
PyErr_SetFromWindowsErr(). However, for some errors, we have additional
information not included in the error code. We handle those here and
if (!PyArg_ParseTuple(args, "O&s:dlsym",
&_parse_voidp, &handle, &name))
return NULL;
+ if (PySys_Audit("ctypes.dlsym/handle", "O", args) < 0) {
+ return NULL;
+ }
ptr = ctypes_dlsym((void*)handle, name);
if (!ptr) {
PyErr_SetString(PyExc_OSError,
&_parse_voidp, &func,
&PyTuple_Type, &arguments))
return NULL;
+ if (PySys_Audit("ctypes.call_function", "nO",
+ (Py_ssize_t)func, arguments) < 0) {
+ return NULL;
+ }
result = _ctypes_callproc((PPROC)func,
arguments,
&_parse_voidp, &func,
&PyTuple_Type, &arguments))
return NULL;
+ if (PySys_Audit("ctypes.call_function", "nO",
+ (Py_ssize_t)func, arguments) < 0) {
+ return NULL;
+ }
result = _ctypes_callproc((PPROC)func,
arguments,
static PyObject *
addressof(PyObject *self, PyObject *obj)
{
- if (CDataObject_Check(obj))
- return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr);
- PyErr_SetString(PyExc_TypeError,
- "invalid type");
- return NULL;
+ if (!CDataObject_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "invalid type");
+ return NULL;
+ }
+ if (PySys_Audit("ctypes.addressof", "O", obj) < 0) {
+ return NULL;
+ }
+ return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr);
}
static int
My_PyObj_FromPtr(PyObject *self, PyObject *args)
{
PyObject *ob;
- if (!PyArg_ParseTuple(args, "O&:PyObj_FromPtr", converter, &ob))
+ if (!PyArg_ParseTuple(args, "O&:PyObj_FromPtr", converter, &ob)) {
return NULL;
+ }
+ if (PySys_Audit("ctypes.PyObj_FromPtr", "O", ob) < 0) {
+ return NULL;
+ }
Py_INCREF(ob);
return ob;
}