add a replacement API for PyCObject, PyCapsule #5630

All stdlib modules with C-APIs now use this.

Patch by Larry Hastings
This commit is contained in:
Benjamin Peterson 2009-05-05 22:31:58 +00:00
parent c679fd8efc
commit b173f7853e
37 changed files with 943 additions and 149 deletions

168
Doc/c-api/capsule.rst Normal file
View File

@ -0,0 +1,168 @@
.. highlightlang:: c
.. _capsules:
Capsules
--------
.. index:: object: Capsule
Refer to :ref:`using-capsules` for more information on using these objects.
.. ctype:: PyCapsule
This subtype of :ctype:`PyObject` represents an opaque value, useful for C
extension modules who need to pass an opaque value (as a :ctype:`void\*`
pointer) through Python code to other C code. It is often used to make a C
function pointer defined in one module available to other modules, so the
regular import mechanism can be used to access C APIs defined in dynamically
loaded modules.
.. ctype:: PyCapsule_Destructor
The type of a destructor callback for a capsule. Defined as::
typedef void (*PyCapsule_Destructor)(PyObject *);
See :cfunc:`PyCapsule_New` for the semantics of PyCapsule_Destructor
callbacks.
.. cfunction:: int PyCapsule_CheckExact(PyObject *p)
Return true if its argument is a :ctype:`PyCapsule`.
.. cfunction:: PyObject* PyCapsule_New(void* pointer, const char* name, PyCapsule_Destructor destructor)
Create a :ctype:`PyCapsule` encapsulating the *pointer*. The *pointer*
argument may not be *NULL*.
The *name* string may either be *NULL* or a pointer to a valid
C string. If non-*NULL*, this string must outlive the capsule.
(Though it is permitted to free it inside the *destructor*.)
If the *destructor* argument is not *NULL*,
it will be called with the capsule ``PyObject *`` when it is destroyed.
If this capsule will be stored as an attribute of a module, it
is strongly suggested that the *name* string be specified as::
modulename.attributename
This will enable other modules to import the capsule
using :cfunc:`PyCapsule_Import`.
Return a valid capsule on success.
On failure, set an exception and return *NULL*.
.. cfunction:: void* PyCapsule_GetPointer(PyObject* capsule, const char* name)
Retrieve the *pointer* stored in the capsule.
The *name* parameter must compare exactly to the name stored in the capsule.
If the name stored in the capsule is *NULL*, the *name* passed in must
also be *NULL*. If the name stored in the capsule is non-*NULL*,
the *name* passed in must also be non-*NULL*, and must match the name
stored in the capsule. Python uses the C function *strcmp* to compare
capsule names.
Return the internal *pointer* on success.
On failure, set an exception and return *NULL*.
.. cfunction:: PyCapsule_Destructor PyCapsule_GetDestructor(PyObject* capsule)
Return the current *destructor* stored in the capsule.
On failure, set an exception and return *NULL*.
It is legal for a capsule to have a *NULL* destructor.
This makes a *NULL* return code somewhat ambiguous;
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
.. cfunction:: void* PyCapsule_GetContext(PyObject* capsule)
Return the current *context* stored in the capsule.
On failure, set an exception and return *NULL*.
It is legal for a capsule to have a *NULL* context.
This makes a *NULL* return code somewhat ambiguous;
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
.. cfunction:: const char* PyCapsule_GetName(PyObject* capsule)
Return the current *name* stored in the capsule.
On failure, set an exception and return *NULL*.
It is legal for a capsule to have a *NULL* name.
This makes a *NULL* return code somewhat ambiguous;
use :cfunc:`PyCapsule_IsValid` or :cfunc:`PyErr_Occurred` to disambugate.
.. cfunction:: void* PyCapsule_Import(const char* name, int no_block)
Import a pointer to a C object from a ``capsule`` attribute in a module.
The *name* parameter should specify the full name to the attribute, as
in *"module.attribute"*.
The *name* stored in the capsule must match this string exactly.
If *no_block* is true, import the module without blocking
(using :cfunc:`PyImport_ImportModuleNoBlock`).
If *no_block* is false, import the module conventionally
(using :cfunc:`PyImport_ImportModule`).
Return the capsule's internal *pointer* on success.
On failure, set an exception and return *NULL*.
Exception: if *PyCapsule_Import* failed to import the module,
and *no_block* was true, no exception is set.
.. cfunction:: int PyCapsule_IsValid(PyObject* capsule, const char* name)
Determines whether or not a :ctype:`PyObject \*` is a valid capsule.
A valid capsule is non-*NULL*, passes :cfunc:`PyCapsule_CheckExact`,
has a non-NULL *pointer*, and its internal name matches the
*name* parameter. (See :cfunc:`PyCapsule_GetPointer` for
information on how capsule names are compared.)
In other words, if :cfunc:`PyCapsule_IsValid` returns a true value,
calls to any of the accessors (any function starting
with :cfunc:`PyCapsule_Get`) are guaranteed to succeed.
Return a nonzero value if the object is valid and matches the name
passed in.
Return 0 otherwise.
This function will not fail.
.. cfunction:: int PyCapsule_SetContext(PyObject* capsule, void* context)
Set the context pointer inside *capsule* to *context*.
Return 0 on success.
Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetDestructor(PyObject* capsule, void (*)(PyObject *) destructor)
Set the destructor inside *capsule* to *destructor*.
Return 0 on success.
Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetName(PyObject* capsule, const char* name)
Set the name inside *capsule* to *name*. If non-*NULL*, the name
must outlive the capsule. If the previous *name* stored in the
capsule was not *NULL*, no attempt is made to free it.
Return 0 on success.
Return nonzero and set an exception on failure.
.. cfunction:: int PyCapsule_SetPointer(PyObject* capsule, void* pointer)
Set the void pointer inside *capsule* to *pointer*. The pointer
may not be *NULL*.
Return 0 on success.
Return nonzero and set an exception on failure.

View File

@ -7,8 +7,11 @@ CObjects
.. index:: object: CObject
Refer to :ref:`using-cobjects` for more information on using these objects.
.. warning::
The CObject API is deprecated as of Python 3.1. Please switch to the new
:ref:`capsules` API.
.. ctype:: PyCObject

View File

@ -101,6 +101,7 @@ Other Objects
descriptor.rst
slice.rst
weakref.rst
capsule.rst
cobject.rst
cell.rst
gen.rst

View File

@ -55,6 +55,45 @@ PyBuffer_FromReadWriteMemory:int:size::
PyBuffer_New:PyObject*::+1:
PyBuffer_New:int:size::
PyCapsule_GetContext:void *:::
PyCapsule_GetContext:PyObject*:self:0:
PyCapsule_GetDestructor:void (*)(PyObject *):::
PyCapsule_GetDestructor:PyObject*:self:0:
PyCapsule_GetName:const char *:::
PyCapsule_GetName:PyObject*:self:0:
PyCapsule_GetPointer:void*:::
PyCapsule_GetPointer:PyObject*:self:0:
PyCapsule_GetPointer:const char *:name::
PyCapsule_Import:void *:::
PyCapsule_Import:const char *:name::
PyCapsule_Import:int:no_block::
PyCapsule_New:PyObject*::+1:
PyCapsule_New:void*:pointer::
PyCapsule_New:const char *:name::
PyCapsule_New::void (* destructor)(PyObject* )::
PyCapsule_SetContext:int:::
PyCapsule_SetContext:PyObject*:self:0:
PyCapsule_SetContext:void *:context::
PyCapsule_SetDestructor:int:::
PyCapsule_SetDestructor:PyObject*:self:0:
PyCapsule_SetDestructor:void (*)(PyObject *):destructor::
PyCapsule_SetName:int:::
PyCapsule_SetName:PyObject*:self:0:
PyCapsule_SetName:const char *:name::
PyCapsule_SetPointer:int:::
PyCapsule_SetPointer:PyObject*:self:0:
PyCapsule_SetPointer:void*:pointer::
PyCObject_AsVoidPtr:void*:::
PyCObject_AsVoidPtr:PyObject*:self:0:

View File

@ -1075,7 +1075,7 @@ already if the symbol ``__cplusplus`` is defined (all recent C++ compilers
define this symbol).
.. _using-cobjects:
.. _using-capsules:
Providing a C API for an Extension Module
=========================================
@ -1111,23 +1111,40 @@ avoid name clashes with other extension modules (as discussed in section
other extension modules must be exported in a different way.
Python provides a special mechanism to pass C-level information (pointers) from
one extension module to another one: CObjects. A CObject is a Python data type
which stores a pointer (:ctype:`void \*`). CObjects can only be created and
one extension module to another one: Capsules. A Capsule is a Python data type
which stores a pointer (:ctype:`void \*`). Capsules can only be created and
accessed via their C API, but they can be passed around like any other Python
object. In particular, they can be assigned to a name in an extension module's
namespace. Other extension modules can then import this module, retrieve the
value of this name, and then retrieve the pointer from the CObject.
value of this name, and then retrieve the pointer from the Capsule.
There are many ways in which CObjects can be used to export the C API of an
extension module. Each name could get its own CObject, or all C API pointers
could be stored in an array whose address is published in a CObject. And the
There are many ways in which Capsules can be used to export the C API of an
extension module. Each function could get its own Capsule, or all C API pointers
could be stored in an array whose address is published in a Capsule. And the
various tasks of storing and retrieving the pointers can be distributed in
different ways between the module providing the code and the client modules.
Whichever method you choose, it's important to name your Capsules properly.
The function :cfunc:`PyCapsule_New` takes a name parameter
(:ctype:`const char \*`); you're permitted to pass in a *NULL* name, but
we strongly encourage you to specify a name. Properly named Capsules provide
a degree of runtime type-safety; there is no feasible way to tell one unnamed
Capsule from another.
In particular, Capsules used to expose C APIs should be given a name following
this convention::
modulename.attributename
The convenience function :cfunc:`PyCapsule_Import` makes it easy to
load a C API provided via a Capsule, but only if the Capsule's name
matches this convention. This behavior gives C API users a high degree
of certainty that the Capsule they load contains the correct C API.
The following example demonstrates an approach that puts most of the burden on
the writer of the exporting module, which is appropriate for commonly used
library modules. It stores all C API pointers (just one in the example!) in an
array of :ctype:`void` pointers which becomes the value of a CObject. The header
array of :ctype:`void` pointers which becomes the value of a Capsule. The header
file corresponding to the module provides a macro that takes care of importing
the module and retrieving its C API pointers; client modules only have to call
this macro before accessing the C API.
@ -1189,8 +1206,8 @@ function must take care of initializing the C API pointer array::
/* Initialize the C API pointer array */
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
/* Create a CObject containing the API pointer array's address */
c_api_object = PyCObject_FromVoidPtr((void *)PySpam_API, NULL);
/* Create a Capsule containing the API pointer array's address */
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
if (c_api_object != NULL)
PyModule_AddObject(m, "_C_API", c_api_object);
@ -1233,21 +1250,14 @@ like this::
#define PySpam_System \
(*(PySpam_System_RETURN (*)PySpam_System_PROTO) PySpam_API[PySpam_System_NUM])
/* Return -1 and set exception on error, 0 on success. */
/* Return -1 on error, 0 on success.
* PyCapsule_Import will set an exception if there's an error.
*/
static int
import_spam(void)
{
PyObject *module = PyImport_ImportModule("spam");
if (module != NULL) {
PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API");
if (c_api_object == NULL)
return -1;
if (PyCObject_Check(c_api_object))
PySpam_API = (void **)PyCObject_AsVoidPtr(c_api_object);
Py_DECREF(c_api_object);
}
return 0;
PySpam_API = (void **)PyCapsule_Import("spam._C_API", 0);
return (PySpam_API != NULL) ? 0 : -1;
}
#endif
@ -1280,11 +1290,11 @@ The main disadvantage of this approach is that the file :file:`spammodule.h` is
rather complicated. However, the basic structure is the same for each function
that is exported, so it has to be learned only once.
Finally it should be mentioned that CObjects offer additional functionality,
Finally it should be mentioned that Capsules offer additional functionality,
which is especially useful for memory allocation and deallocation of the pointer
stored in a CObject. The details are described in the Python/C API Reference
Manual in the section :ref:`cobjects` and in the implementation of CObjects (files
:file:`Include/cobject.h` and :file:`Objects/cobject.c` in the Python source
stored in a Capsule. The details are described in the Python/C API Reference
Manual in the section :ref:`capsules` and in the implementation of Capsules (files
:file:`Include/pycapsule.h` and :file:`Objects/pycapsule.c` in the Python source
code distribution).
.. rubric:: Footnotes

View File

@ -89,6 +89,7 @@
#include "classobject.h"
#include "fileobject.h"
#include "cobject.h"
#include "pycapsule.h"
#include "traceback.h"
#include "sliceobject.h"
#include "cellobject.h"

View File

@ -1,10 +1,8 @@
/* C objects to be exported from one extension module to another.
/*
C objects are used for communication between extension modules.
They provide a way for an extension module to export a C interface
to other extension modules, so that extension modules can use the
Python import mechanism to link to one another.
The CObject module is now *deprecated* as of Python 3.1.
Please use the Capsule API instead; see "pycapsule.h".
*/

View File

@ -158,9 +158,8 @@ typedef struct {
} PyDateTime_CAPI;
#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
/* "magic" constant used to partially protect against developer mistakes. */
#define DATETIME_API_MAGIC 0x414548d5
#ifdef Py_BUILD_CORE
@ -186,15 +185,7 @@ typedef struct {
static PyDateTime_CAPI *PyDateTimeAPI;
#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import("datetime", \
"datetime_CAPI")
/* This macro would be used if PyCObject_ImportEx() was created.
#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_ImportEx("datetime", \
"datetime_CAPI", \
DATETIME_API_MAGIC)
*/
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
/* Macros for type checking when not building the Python core. */
#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType)

View File

@ -75,6 +75,9 @@ typedef struct {
#define PyCursesWindow_Check(v) (Py_TYPE(v) == &PyCursesWindow_Type)
#define PyCurses_CAPSULE_NAME "_curses._C_API"
#ifdef CURSES_MODULE
/* This section is used when compiling _cursesmodule.c */
@ -89,16 +92,8 @@ static void **PyCurses_API;
#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;}
#define import_curses() \
{ \
PyObject *module = PyImport_ImportModuleNoBlock("_curses"); \
if (module != NULL) { \
PyObject *module_dict = PyModule_GetDict(module); \
PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \
if (PyCObject_Check(c_api_object)) { \
PyCurses_API = (void **)PyCObject_AsVoidPtr(c_api_object); \
} \
} \
}
PyCurses_API = (void **)PyCapsule_Import(PyCurses_CAPSULE_NAME, 1);
#endif
/* general error messages */

57
Include/pycapsule.h Normal file
View File

@ -0,0 +1,57 @@
/* Capsule objects let you wrap a C "void *" pointer in a Python
object. They're a way of passing data through the Python interpreter
without creating your own custom type.
Capsules are used for communication between extension modules.
They provide a way for an extension module to export a C interface
to other extension modules, so that extension modules can use the
Python import mechanism to link to one another.
For more information, please see "c-api/capsule.html" in the
documentation.
*/
#ifndef Py_CAPSULE_H
#define Py_CAPSULE_H
#ifdef __cplusplus
extern "C" {
#endif
PyAPI_DATA(PyTypeObject) PyCapsule_Type;
typedef void (*PyCapsule_Destructor)(PyObject *);
#define PyCapsule_CheckExact(op) (Py_TYPE(op) == &PyCapsule_Type)
PyAPI_FUNC(PyObject *) PyCapsule_New(
void *pointer,
const char *name,
PyCapsule_Destructor destructor);
PyAPI_FUNC(void *) PyCapsule_GetPointer(PyObject *capsule, const char *name);
PyAPI_FUNC(PyCapsule_Destructor) PyCapsule_GetDestructor(PyObject *capsule);
PyAPI_FUNC(const char *) PyCapsule_GetName(PyObject *capsule);
PyAPI_FUNC(void *) PyCapsule_GetContext(PyObject *capsule);
PyAPI_FUNC(int) PyCapsule_IsValid(PyObject *capsule, const char *name);
PyAPI_FUNC(int) PyCapsule_SetPointer(PyObject *capsule, void *pointer);
PyAPI_FUNC(int) PyCapsule_SetDestructor(PyObject *capsule, PyCapsule_Destructor destructor);
PyAPI_FUNC(int) PyCapsule_SetName(PyObject *capsule, const char *name);
PyAPI_FUNC(int) PyCapsule_SetContext(PyObject *capsule, void *context);
PyAPI_FUNC(void *) PyCapsule_Import(const char *name, int no_block);
#ifdef __cplusplus
}
#endif
#endif /* !Py_CAPSULE_H */

View File

@ -4,6 +4,7 @@
/* note: you must import expat.h before importing this module! */
#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0"
#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI"
struct PyExpat_CAPI
{

View File

@ -6,7 +6,9 @@
extern "C" {
#endif
/* revised ucnhash CAPI interface (exported through a PyCObject) */
/* revised ucnhash CAPI interface (exported through a "wrapper") */
#define PyUnicodeData_CAPSULE_NAME "unicodedata.ucnhash_CAPI"
typedef struct {

View File

@ -644,7 +644,7 @@ class SizeofTest(unittest.TestCase):
def delx(self): del self.__x
x = property(getx, setx, delx, "")
check(x, size(h + '4Pi'))
# PyCObject
# PyCapsule
# XXX
# rangeiterator
check(iter(range(1)), size(h + '4l'))

View File

@ -344,6 +344,7 @@ OBJECT_OBJS= \
Objects/moduleobject.o \
Objects/object.o \
Objects/obmalloc.o \
Objects/capsule.o \
Objects/rangeobject.o \
Objects/setobject.o \
Objects/sliceobject.o \
@ -654,6 +655,7 @@ PYTHON_HEADERS= \
Include/pgen.h \
Include/pgenheaders.h \
Include/pyarena.h \
Include/pycapsule.h \
Include/pyctype.h \
Include/pydebug.h \
Include/pyerrors.h \

View File

@ -226,6 +226,11 @@ Tests
support.EnvironmentVarGuard objects restored the environment variables
incorrectly on __exit__.
C-API
-----
- Issue #5630: A replacement PyCObject API, PyCapsule, has been added.
What's New in Python 3.1 alpha 2?
=================================

View File

@ -78,6 +78,16 @@
#define DONT_USE_SEH
#endif
#define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem"
static void pymem_destructor(PyObject *ptr)
{
void *p = PyCapsule_GetPointer(ptr, CTYPES_CAPSULE_NAME_PYMEM);
if (p) {
PyMem_Free(p);
}
}
/*
ctypes maintains thread-local storage that has space for two error numbers:
private copies of the system 'errno' value and, on Windows, the system error code
@ -136,7 +146,7 @@ _ctypes_get_errobj(int **pspace)
if (space == NULL)
return NULL;
memset(space, 0, sizeof(int) * 2);
errobj = PyCObject_FromVoidPtr(space, PyMem_Free);
errobj = PyCapsule_New(space, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor);
if (errobj == NULL)
return NULL;
if (-1 == PyDict_SetItem(dict, error_object_name,
@ -145,7 +155,7 @@ _ctypes_get_errobj(int **pspace)
return NULL;
}
}
*pspace = (int *)PyCObject_AsVoidPtr(errobj);
*pspace = (int *)PyCapsule_GetPointer(errobj, CTYPES_CAPSULE_NAME_PYMEM);
return errobj;
}
@ -658,7 +668,7 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
return -1;
}
memset(pa->value.p, 0, size);
pa->keep = PyCObject_FromVoidPtr(pa->value.p, PyMem_Free);
pa->keep = PyCapsule_New(pa->value.p, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor);
if (!pa->keep) {
PyMem_Free(pa->value.p);
return -1;

View File

@ -6,6 +6,18 @@
#endif
#include "ctypes.h"
#define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem"
static void pymem_destructor(PyObject *ptr)
{
void *p = PyCapsule_GetPointer(ptr, CTYPES_CFIELD_CAPSULE_NAME_PYMEM);
if (p) {
PyMem_Free(p);
}
}
/******************************************************************/
/*
PyCField_Type
@ -1477,7 +1489,7 @@ Z_set(void *ptr, PyObject *value, Py_ssize_t size)
return PyErr_NoMemory();
}
memset(buffer, 0, size);
keep = PyCObject_FromVoidPtr(buffer, PyMem_Free);
keep = PyCapsule_New(buffer, CTYPES_CFIELD_CAPSULE_NAME_PYMEM, pymem_destructor);
if (!keep) {
Py_DECREF(value);
PyMem_Free(buffer);

View File

@ -104,6 +104,7 @@ char *PyCursesVersion = "2.2";
#include "Python.h"
#ifdef __osf__
#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */
#endif
@ -174,7 +175,7 @@ static int initialisedcolors = FALSE;
/*
* Check the return code from a curses function and return None
* or raise an exception as appropriate. These are exported using the
* CObject API.
* capsule API.
*/
static PyObject *
@ -2827,8 +2828,8 @@ PyInit__curses(void)
return NULL;
ModDict = d; /* For PyCurses_InitScr to use later */
/* Add a CObject for the C API */
c_api_object = PyCObject_FromVoidPtr((void *)PyCurses_API, NULL);
/* Add a capsule for the C API */
c_api_object = PyCapsule_New(PyCurses_API, PyCurses_CAPSULE_NAME, NULL);
PyDict_SetItemString(d, "_C_API", c_api_object);
Py_DECREF(c_api_object);

View File

@ -2809,7 +2809,7 @@ PyInit__elementtree(void)
#if defined(USE_PYEXPAT_CAPI)
/* link against pyexpat, if possible */
capi = PyCObject_Import("pyexpat", "expat_CAPI");
capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
if (capi &&
strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0 &&
capi->size <= sizeof(*expat_capi) &&

View File

@ -71,6 +71,8 @@ enum py_ssl_version {
/* Include symbols from _socket module */
#include "socketmodule.h"
static PySocketModule_APIObject PySocketModule;
#if defined(HAVE_POLL_H)
#include <poll.h>
#elif defined(HAVE_SYS_POLL_H)
@ -1626,6 +1628,7 @@ PyMODINIT_FUNC
PyInit__ssl(void)
{
PyObject *m, *d;
PySocketModule_APIObject *socket_api;
if (PyType_Ready(&PySSL_Type) < 0)
return NULL;
@ -1636,8 +1639,10 @@ PyInit__ssl(void)
d = PyModule_GetDict(m);
/* Load _socket module and its C API */
if (PySocketModule_ImportModuleAndAPI())
socket_api = PySocketModule_ImportModuleAndAPI();
if (!socket_api)
return NULL;
PySocketModule = *socket_api;
/* Init OpenSSL */
SSL_load_error_strings();

View File

@ -1102,6 +1102,155 @@ test_string_to_double(PyObject *self) {
}
/* Coverage testing of capsule objects. */
static const char *capsule_name = "capsule name";
static char *capsule_pointer = "capsule pointer";
static char *capsule_context = "capsule context";
static const char *capsule_error = NULL;
static int
capsule_destructor_call_count = 0;
static void
capsule_destructor(PyObject *o) {
capsule_destructor_call_count++;
if (PyCapsule_GetContext(o) != capsule_context) {
capsule_error = "context did not match in destructor!";
} else if (PyCapsule_GetDestructor(o) != capsule_destructor) {
capsule_error = "destructor did not match in destructor! (woah!)";
} else if (PyCapsule_GetName(o) != capsule_name) {
capsule_error = "name did not match in destructor!";
} else if (PyCapsule_GetPointer(o, capsule_name) != capsule_pointer) {
capsule_error = "pointer did not match in destructor!";
}
}
typedef struct {
char *name;
char *module;
char *attribute;
} known_capsule;
static PyObject *
test_capsule(PyObject *self, PyObject *args)
{
PyObject *object;
const char *error = NULL;
void *pointer;
void *pointer2;
known_capsule known_capsules[] = {
#define KNOWN_CAPSULE(module, name) { module "." name, module, name }
KNOWN_CAPSULE("_socket", "CAPI"),
KNOWN_CAPSULE("_curses", "_C_API"),
KNOWN_CAPSULE("datetime", "datetime_CAPI"),
{ NULL, NULL },
};
known_capsule *known = &known_capsules[0];
#define FAIL(x) { error = (x); goto exit; }
#define CHECK_DESTRUCTOR \
if (capsule_error) { \
FAIL(capsule_error); \
} \
else if (!capsule_destructor_call_count) { \
FAIL("destructor not called!"); \
} \
capsule_destructor_call_count = 0; \
object = PyCapsule_New(capsule_pointer, capsule_name, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
Py_DECREF(object);
CHECK_DESTRUCTOR;
object = PyCapsule_New(known, "ignored", NULL);
PyCapsule_SetPointer(object, capsule_pointer);
PyCapsule_SetName(object, capsule_name);
PyCapsule_SetDestructor(object, capsule_destructor);
PyCapsule_SetContext(object, capsule_context);
capsule_destructor(object);
CHECK_DESTRUCTOR;
/* intentionally access using the wrong name */
pointer2 = PyCapsule_GetPointer(object, "the wrong name");
if (!PyErr_Occurred()) {
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
PyErr_Clear();
if (pointer2) {
if (pointer2 == capsule_pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned the internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have "
"returned NULL pointer but did not!");
}
}
PyCapsule_SetDestructor(object, NULL);
Py_DECREF(object);
if (capsule_destructor_call_count) {
FAIL("destructor called when it should not have been!");
}
for (known = &known_capsules[0]; known->module != NULL; known++) {
/* yeah, ordinarily I wouldn't do this either,
but it's fine for this test harness.
*/
static char buffer[256];
#undef FAIL
#define FAIL(x) \
{ \
sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \
x, known->module, known->attribute); \
error = buffer; \
goto exit; \
} \
PyObject *module = PyImport_ImportModule(known->module);
if (module) {
pointer = PyCapsule_Import(known->name, 0);
if (!pointer) {
Py_DECREF(module);
FAIL("PyCapsule_GetPointer returned NULL unexpectedly!");
}
object = PyObject_GetAttrString(module, known->attribute);
if (!object) {
Py_DECREF(module);
return NULL;
}
pointer2 = PyCapsule_GetPointer(object,
"weebles wobble but they don't fall down");
if (!PyErr_Occurred()) {
Py_DECREF(object);
Py_DECREF(module);
FAIL("PyCapsule_GetPointer should have failed but did not!");
}
PyErr_Clear();
if (pointer2) {
Py_DECREF(module);
Py_DECREF(object);
if (pointer2 == pointer) {
FAIL("PyCapsule_GetPointer should not have"
" returned its internal pointer!");
} else {
FAIL("PyCapsule_GetPointer should have"
" returned NULL pointer but did not!");
}
}
Py_DECREF(object);
Py_DECREF(module);
}
}
exit:
if (error) {
return raiseTestError("test_capsule", error);
}
Py_RETURN_NONE;
#undef FAIL
}
#ifdef HAVE_GETTIMEOFDAY
/* Profiling of integer performance */
static void print_delta(int test, struct timeval *s, struct timeval *e)
@ -1280,9 +1429,10 @@ static PyMethodDef TestMethods[] = {
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},
{"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS},
{"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS},
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
{"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS,
PyDoc_STR("This is a pretty normal docstring.")},
{"test_string_to_double", (PyCFunction)test_string_to_double, METH_NOARGS},
{"test_capsule", (PyCFunction)test_capsule, METH_NOARGS},
{"getargs_tuple", getargs_tuple, METH_VARARGS},
{"getargs_keywords", (PyCFunction)getargs_keywords,

View File

@ -239,6 +239,8 @@ static const struct dbcs_map *mapping_list;
static const MultibyteCodec *codec_list = \
(const MultibyteCodec *)_codec_list;
static PyObject *
getmultibytecodec(void)
{
@ -284,7 +286,7 @@ getcodec(PyObject *self, PyObject *encoding)
return NULL;
}
codecobj = PyCObject_FromVoidPtr((void *)codec, NULL);
codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
if (codecobj == NULL)
return NULL;
@ -309,7 +311,7 @@ register_maps(PyObject *module)
int r;
strcpy(mhname + sizeof("__map_") - 1, h->charset);
r = PyModule_AddObject(module, mhname,
PyCObject_FromVoidPtr((void *)h, NULL));
PyCapsule_New((void *)h, PyMultibyteCodec_CAPSULE_NAME, NULL));
if (r == -1)
return -1;
}
@ -364,14 +366,14 @@ importmap(const char *modname, const char *symbol,
o = PyObject_GetAttrString(mod, (char*)symbol);
if (o == NULL)
goto errorexit;
else if (!PyCObject_Check(o)) {
else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
PyErr_SetString(PyExc_ValueError,
"map data must be a CObject.");
"map data must be a Capsule.");
goto errorexit;
}
else {
struct dbcs_map *map;
map = PyCObject_AsVoidPtr(o);
map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
if (encmap != NULL)
*encmap = map->encmap;
if (decmap != NULL)

View File

@ -1793,12 +1793,12 @@ __create_codec(PyObject *ignore, PyObject *arg)
MultibyteCodecObject *self;
MultibyteCodec *codec;
if (!PyCObject_Check(arg)) {
if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) {
PyErr_SetString(PyExc_ValueError, "argument type invalid");
return NULL;
}
codec = PyCObject_AsVoidPtr(arg);
codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME);
if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
return NULL;

View File

@ -132,6 +132,9 @@ typedef struct {
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
#define MBENC_MAX MBENC_FLUSH
#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*"
#ifdef __cplusplus
}
#endif

View File

@ -4792,11 +4792,10 @@ PyInit_datetime(void)
Py_INCREF(&PyDateTime_TZInfoType);
PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType);
x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC,
NULL);
if (x == NULL)
return NULL;
PyModule_AddObject(m, "datetime_CAPI", x);
x = PyCapsule_New(&CAPI, PyDateTime_CAPSULE_NAME, NULL);
if (x == NULL)
return NULL;
PyModule_AddObject(m, "datetime_CAPI", x);
/* A 4-year cycle has an extra leap day over what we'd get from
* pasting together 4 single years.

View File

@ -1987,8 +1987,8 @@ MODULE_INITFUNC(void)
capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler;
capi.SetUserData = XML_SetUserData;
/* export as cobject */
capi_object = PyCObject_FromVoidPtr(&capi, NULL);
/* export using capsule */
capi_object = PyCapsule_New(&capi, PyExpat_CAPSULE_NAME, NULL);
if (capi_object)
PyModule_AddObject(m, "expat_CAPI", capi_object);
return m;

View File

@ -4146,6 +4146,14 @@ PySocketModule_APIObject PySocketModuleAPI =
NULL
};
PySocketModule_APIObject *
PySocketModule_ImportModuleAndAPI(void)
{
void *api;
api = PyCapsule_Import(PySocket_CAPSULE_NAME, 1);;
return (PySocketModule_APIObject *)api;
}
/* Initialize the _socket module.
@ -4231,7 +4239,7 @@ PyInit__socket(void)
/* Export C API */
if (PyModule_AddObject(m, PySocket_CAPI_NAME,
PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL)
PyCapsule_New(&PySocketModuleAPI, PySocket_CAPSULE_NAME, NULL)
) != 0)
return NULL;

View File

@ -78,6 +78,7 @@ extern "C" {
/* Python module and C API name */
#define PySocket_MODULE_NAME "_socket"
#define PySocket_CAPI_NAME "CAPI"
#define PySocket_CAPSULE_NAME PySocket_MODULE_NAME "." PySocket_CAPI_NAME
/* Abstract the socket file descriptor type */
#ifdef MS_WINDOWS
@ -142,12 +143,12 @@ typedef struct {
the _socket module. Since cross-DLL linking introduces a lot of
problems on many platforms, the "trick" is to wrap the
C API of a module in a struct which then gets exported to
other modules via a PyCObject.
other modules via a PyCapsule.
The code in socketmodule.c defines this struct (which currently
only contains the type object reference, but could very
well also include other C APIs needed by other modules)
and exports it as PyCObject via the module dictionary
and exports it as PyCapsule via the module dictionary
under the name "CAPI".
Other modules can now include the socketmodule.h file
@ -212,49 +213,11 @@ typedef struct {
...
*/
static
PySocketModule_APIObject PySocketModule;
/* You *must* call this before using any of the functions in
PySocketModule and check its outcome; otherwise all accesses will
result in a segfault. Returns 0 on success. */
#ifndef DPRINTF
# define DPRINTF if (0) printf
#endif
static
int PySocketModule_ImportModuleAndAPI(void)
{
PyObject *mod = 0, *v = 0;
char *apimodule = PySocket_MODULE_NAME;
char *apiname = PySocket_CAPI_NAME;
void *api;
DPRINTF("Importing the %s C API...\n", apimodule);
mod = PyImport_ImportModuleNoBlock(apimodule);
if (mod == NULL)
goto onError;
DPRINTF(" %s package found\n", apimodule);
v = PyObject_GetAttrString(mod, apiname);
if (v == NULL)
goto onError;
Py_DECREF(mod);
DPRINTF(" API object %s found\n", apiname);
api = PyCObject_AsVoidPtr(v);
if (api == NULL)
goto onError;
Py_DECREF(v);
memcpy(&PySocketModule, api, sizeof(PySocketModule));
DPRINTF(" API object loaded and initialized.\n");
return 0;
onError:
DPRINTF(" not found.\n");
Py_XDECREF(mod);
Py_XDECREF(v);
return -1;
}
PyAPI_FUNC(PySocketModule_APIObject *) PySocketModule_ImportModuleAndAPI(void);
#endif /* !PySocket_BUILDING_SOCKET */

View File

@ -1275,7 +1275,7 @@ PyInit_unicodedata(void)
PyModule_AddObject(m, "ucd_3_2_0", v);
/* Export C API */
v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL);
v = PyCapsule_New((void *)&hashAPI, PyUnicodeData_CAPSULE_NAME, NULL);
if (v != NULL)
PyModule_AddObject(m, "ucnhash_CAPI", v);
return m;

324
Objects/capsule.c Normal file
View File

@ -0,0 +1,324 @@
/* Wrap void * pointers to be passed between C modules */
#include "Python.h"
/* Internal structure of PyCapsule */
typedef struct {
PyObject_HEAD
void *pointer;
const char *name;
void *context;
PyCapsule_Destructor destructor;
} PyCapsule;
static int
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
{
if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
PyErr_SetString(PyExc_ValueError, invalid_capsule);
return 0;
}
return 1;
}
#define is_legal_capsule(capsule, name) \
(_is_legal_capsule(capsule, \
name " called with invalid PyCapsule object"))
static int
name_matches(const char *name1, const char *name2) {
/* if either is NULL, */
if (!name1 || !name2) {
/* they're only the same if they're both NULL. */
return name2 == name2;
}
return !strcmp(name1, name2);
}
PyObject *
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
{
PyCapsule *capsule;
if (!pointer) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
return NULL;
}
capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
if (capsule == NULL) {
return NULL;
}
capsule->pointer = pointer;
capsule->name = name;
capsule->context = NULL;
capsule->destructor = destructor;
return (PyObject *)capsule;
}
int
PyCapsule_IsValid(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
return (capsule != NULL &&
PyCapsule_CheckExact(capsule) &&
capsule->pointer != NULL &&
name_matches(capsule->name, name));
}
void *
PyCapsule_GetPointer(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
return NULL;
}
if (!name_matches(name, capsule->name)) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
return NULL;
}
return capsule->pointer;
}
const char *
PyCapsule_GetName(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
return NULL;
}
return capsule->name;
}
PyCapsule_Destructor
PyCapsule_GetDestructor(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
return NULL;
}
return capsule->destructor;
}
void *
PyCapsule_GetContext(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
return NULL;
}
return capsule->context;
}
int
PyCapsule_SetPointer(PyObject *o, void *pointer)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!pointer) {
PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
return -1;
}
if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
return -1;
}
capsule->pointer = pointer;
return 0;
}
int
PyCapsule_SetName(PyObject *o, const char *name)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
return -1;
}
capsule->name = name;
return 0;
}
int
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
return -1;
}
capsule->destructor = destructor;
return 0;
}
int
PyCapsule_SetContext(PyObject *o, void *context)
{
PyCapsule *capsule = (PyCapsule *)o;
if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
return -1;
}
capsule->context = context;
return 0;
}
void *
PyCapsule_Import(const char *name, int no_block)
{
PyObject *object = NULL;
void *return_value = NULL;
char *trace;
int name_length = (strlen(name) + 1) * sizeof(char);
char *name_dup = (char *)PyMem_MALLOC(name_length);
if (!name_dup) {
return NULL;
}
memcpy(name_dup, name, name_length);
trace = name_dup;
while (trace) {
char *dot = strchr(trace, '.');
if (dot) {
*dot++ = '\0';
}
if (object == NULL) {
if (no_block) {
object = PyImport_ImportModuleNoBlock(trace);
} else {
object = PyImport_ImportModule(trace);
if (!object) {
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
}
}
} else {
PyObject *object2 = PyObject_GetAttrString(object, trace);
Py_DECREF(object);
object = object2;
}
if (!object) {
goto EXIT;
}
trace = dot;
}
/* compare attribute name to module.name by hand */
if (PyCapsule_IsValid(object, name)) {
PyCapsule *capsule = (PyCapsule *)object;
return_value = capsule->pointer;
} else {
PyErr_Format(PyExc_AttributeError,
"PyCapsule_Import \"%s\" is not valid",
name);
}
EXIT:
Py_XDECREF(object);
if (name_dup) {
PyMem_FREE(name_dup);
}
return return_value;
}
static void
capsule_dealloc(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
if (capsule->destructor) {
capsule->destructor(o);
}
PyObject_DEL(o);
}
static PyObject *
capsule_repr(PyObject *o)
{
PyCapsule *capsule = (PyCapsule *)o;
const char *name;
const char *quote;
if (capsule->name) {
quote = "\"";
name = capsule->name;
} else {
quote = "";
name = "NULL";
}
return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
quote, name, quote, capsule);
}
PyDoc_STRVAR(PyCapsule_Type__doc__,
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
object. They're a way of passing data through the Python interpreter\n\
without creating your own custom type.\n\
\n\
Capsules are used for communication between extension modules.\n\
They provide a way for an extension module to export a C interface\n\
to other extension modules, so that extension modules can use the\n\
Python import mechanism to link to one another.\n\
");
PyTypeObject PyCapsule_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"PyCapsule", /*tp_name*/
sizeof(PyCapsule), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
capsule_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_reserved*/
capsule_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
0, /*tp_flags*/
PyCapsule_Type__doc__ /*tp_doc*/
};

View File

@ -1716,11 +1716,14 @@ _Py_GetObjects(PyObject *self, PyObject *args)
#endif
/* Hack to force loading of cobject.o */
PyTypeObject *_Py_cobject_hack = &PyCObject_Type;
/* Hack to force loading of pycapsule.o */
PyTypeObject *_PyCapsule_hack = &PyCapsule_Type;
/* Hack to force loading of abstract.o */
Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size;

View File

@ -3381,16 +3381,7 @@ PyObject *PyUnicode_DecodeUnicodeEscape(const char *s,
message = "malformed \\N character escape";
if (ucnhash_CAPI == NULL) {
/* load the unicode data module */
PyObject *m, *api;
m = PyImport_ImportModuleNoBlock("unicodedata");
if (m == NULL)
goto ucnhashError;
api = PyObject_GetAttrString(m, "ucnhash_CAPI");
Py_DECREF(m);
if (api == NULL)
goto ucnhashError;
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCObject_AsVoidPtr(api);
Py_DECREF(api);
ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import(PyUnicodeData_CAPSULE_NAME, 1);
if (ucnhash_CAPI == NULL)
goto ucnhashError;
}

View File

@ -209,6 +209,19 @@ EXPORTS
"PyInstance_Type"
"PyMethod_Type"
; From python26_s.lib(capsule)
"PyCapsule_GetContext"
"PyCapsule_GetDestructor"
"PyCapsule_GetName"
"PyCapsule_GetPointer"
"PyCapsule_Import"
"PyCapsule_IsValid"
"PyCapsule_New"
"PyCapsule_SetContext"
"PyCapsule_SetDestructor"
"PyCapsule_SetName"
"PyCapsule_SetPointer"
; From python26_s.lib(cobject)
"PyCObject_FromVoidPtr"
"PyCObject_FromVoidPtrAndDesc"

View File

@ -6,6 +6,7 @@ DATA MULTIPLE NONSHARED
EXPORTS
; Data
PyCFunction_Type
PyCapsule_Type
PyCObject_Type
PyClass_Type
PyCode_Type
@ -73,7 +74,7 @@ EXPORTS
_Py_TrueStruct
_Py_ZeroStruct
_Py_abstract_hack
_Py_cobject_hack
_Py_capsule_hack
_Py_re_syntax
_Py_re_syntax_table
@ -87,6 +88,17 @@ EXPORTS
PyCFunction_GetFunction
PyCFunction_GetSelf
PyCFunction_New
PyCapsule_GetContext
PyCapsule_GetDestructor
PyCapsule_GetName
PyCapsule_GetPointer
PyCapsule_Import
PyCapsule_IsValid
PyCapsule_New
PyCapsule_SetContext
PyCapsule_SetDestructor
PyCapsule_SetName
PyCapsule_SetPointer
PyCObject_AsVoidPtr
PyCObject_FromVoidPtrAndDesc
PyCObject_FromVoidPtr

View File

@ -846,6 +846,7 @@
RelativePath="..\Include\pyarena.h"
>
</File>
<File RelativePath="..\Include\pycapsule.h"></File>
<File
RelativePath="..\Include\pyctype.h"
>
@ -1374,6 +1375,10 @@
RelativePath="..\Objects\bytesobject.c"
>
</File>
<File
RelativePath="..\Objects\capsule.c"
>
</File>
<File
RelativePath="..\Objects\cellobject.c"
>

View File

@ -190,6 +190,8 @@ static int compiler_call_helper(struct compiler *c, int n,
static PyCodeObject *assemble(struct compiler *, int addNone);
static PyObject *__doc__;
#define COMPILER_CAPSULE_NAME_COMPILER_UNIT "compile.c compiler unit"
PyObject *
_Py_Mangle(PyObject *privateobj, PyObject *ident)
{
@ -506,13 +508,13 @@ compiler_enter_scope(struct compiler *c, identifier name, void *key,
/* Push the old compiler_unit on the stack. */
if (c->u) {
PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL);
if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) {
Py_XDECREF(wrapper);
PyObject *capsule = PyCapsule_New(c->u, COMPILER_CAPSULE_NAME_COMPILER_UNIT, NULL);
if (!capsule || PyList_Append(c->c_stack, capsule) < 0) {
Py_XDECREF(capsule);
compiler_unit_free(u);
return 0;
}
Py_DECREF(wrapper);
Py_DECREF(capsule);
u->u_private = c->u->u_private;
Py_XINCREF(u->u_private);
}
@ -529,15 +531,15 @@ static void
compiler_exit_scope(struct compiler *c)
{
int n;
PyObject *wrapper;
PyObject *capsule;
c->c_nestlevel--;
compiler_unit_free(c->u);
/* Restore c->u to the parent unit. */
n = PyList_GET_SIZE(c->c_stack) - 1;
if (n >= 0) {
wrapper = PyList_GET_ITEM(c->c_stack, n);
c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper);
capsule = PyList_GET_ITEM(c->c_stack, n);
c->u = (struct compiler_unit *)PyCapsule_GetPointer(capsule, COMPILER_CAPSULE_NAME_COMPILER_UNIT);
assert(c->u);
/* we are deleting from a list so this really shouldn't fail */
if (PySequence_DelItem(c->c_stack, n) < 0)

View File

@ -139,22 +139,33 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
/* Handle cleanup of allocated memory in case of exception */
#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr"
#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer"
static void
cleanup_ptr(void *ptr)
cleanup_ptr(PyObject *self)
{
PyMem_FREE(ptr);
void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR);
if (ptr) {
PyMem_FREE(ptr);
}
}
static void
cleanup_buffer(void *ptr)
cleanup_buffer(PyObject *self)
{
PyBuffer_Release((Py_buffer *) ptr);
Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER);
if (ptr) {
PyBuffer_Release(ptr);
}
}
static int
addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr)
{
PyObject *cobj;
const char *name;
if (!*freelist) {
*freelist = PyList_New(0);
if (!*freelist) {
@ -162,7 +173,15 @@ addcleanup(void *ptr, PyObject **freelist, void (*destr)(void *))
return -1;
}
}
cobj = PyCObject_FromVoidPtr(ptr, destr);
if (destr == cleanup_ptr) {
name = GETARGS_CAPSULE_NAME_CLEANUP_PTR;
} else if (destr == cleanup_buffer) {
name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER;
} else {
return -1;
}
cobj = PyCapsule_New(ptr, name, destr);
if (!cobj) {
destr(ptr);
return -1;
@ -183,8 +202,7 @@ cleanreturn(int retval, PyObject *freelist)
don't get called. */
Py_ssize_t len = PyList_GET_SIZE(freelist), i;
for (i = 0; i < len; i++)
((PyCObject *) PyList_GET_ITEM(freelist, i))
->destructor = NULL;
PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL);
}
Py_XDECREF(freelist);
return retval;