Staging
v0.5.1
Revision 5d8ef8bc3f7307cd15f9d82ad4846e82b498ae88 authored by Miss Islington (bot) on 13 October 2018, 04:07:01 UTC, committed by Ned Deily on 13 October 2018, 04:07:01 UTC
With macOS framework builds, test case test_nonexisting_script in
test_nonexisting_script fails because the test case assumes that
the file name in sys.executable will appear in the error message.
For macOS framework builds, sys.executable is the file name of the
stub launcher and its file name bears no relationship to the file
name of the actual python executable.  For now, skip the test in
this case.
(cherry picked from commit f6c29a65e2a6da5c0014c868cf963c975b74e72b)

Co-authored-by: Ned Deily <nad@python.org>
1 parent d4ed880
Raw File
capsule.c
/* 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 name1 == 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;
    size_t 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*/
};


back to top