Ejemplo n.º 1
0
void CAssocManager::Assoc(void *handle, ui_assoc_object *object)
{
	ASSERT_GIL_HELD;  // we rely on the GIL to serialize access to our map...
	ASSERT(handle);
#ifdef DEBUG
	// overwriting an existing entry probably means we are failing to
	// detect the death of the old object and its address has been reused.
	if (object) { // might just be nuking ours, so we expect to find outself!
		PyObject *existing_weakref;
		if (map.Lookup(handle, (void *&)existing_weakref)) {
			TRACE("CAssocManager::Assoc overwriting existing assoc\n");
			DebugBreak();
		}
	}
#endif
	RemoveAssoc(handle);
	if (object) {
		PyObject *weakref = PyWeakref_NewRef(object, NULL);
		if (weakref)
			// reference owned by the map.
			map.SetAt(handle, weakref);
		else {
			TRACE("Failed to create weakref\n");
			gui_print_error();
			DebugBreak();
		}
	}
}
Ejemplo n.º 2
0
QtBaseWidget::QtBaseWidget(PyQtGuiObject* control) :
	QWidget(control->getParentWidget().scoped().ptr),
	controlRef(NULL),
	handleResize(false)
{	
	selfRef = boost::shared_ptr<LockedRef>(new LockedRef(*this));
	control->widget = QtBaseWidget::WeakRef(*this);	
		
	{
		PyScopedGIL gil;
		controlRef = (PyWeakReference*) PyWeakref_NewRef((PyObject*) control, NULL);
		canHaveFocus = attrChain_bool_default(control->attr, "canHaveFocus", false);
	}
	
	if(!controlRef)
		printf("QtBaseWidget: cannot create controlRef\n");

	if(canHaveFocus)
		this->setFocusPolicy(Qt::StrongFocus);
	else
		this->setFocusPolicy(Qt::NoFocus);
		
	//if(canHaveFocus)
	//	[self setDrawsBackground:YES];
}
Ejemplo n.º 3
0
int WeakSet_Add(PyObject *_self,PyObject *key){
    WeakSet *self = (WeakSet *)_self;

    int r = WeakSet_Contains((PyObject *)self,key);
    if (r) return r; // This also propegates errors.

    remover_closure *closure = PyMem_Malloc(sizeof(remover_closure));
    closure->setref = self->selfref;
    Py_INCREF(closure->setref);
    PyObject *remover = CFunction_new(WeakSet_remover,
                                      WeakSet_remover_dealloc,
                                      closure);

    PyObject *ref = PyWeakref_NewRef((PyObject *)key,remover);
    if (!ref) goto bail;

    r = PySet_Add(self->set,ref);
    if (r) goto bail;

    r = 0;
    goto done;
bail:
    r = -1;
done:
    Py_XDECREF(remover);
    Py_XDECREF(ref);
    return r;
}
Ejemplo n.º 4
0
PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient)
{
    if (nurse == Py_None)
        return incref(nurse);
    
    if (life_support_type.ob_type == 0)
    {
        life_support_type.ob_type = &PyType_Type;
        PyType_Ready(&life_support_type);
    }
    
    life_support* system = PyObject_New(life_support, &life_support_type);
    if (!system)
        return 0;

    system->patient = 0;
    
    // We're going to leak this reference, but don't worry; the
    // life_support system decrements it when the nurse dies.
    PyObject* weakref = PyWeakref_NewRef(nurse, (PyObject*)system);
    if (!weakref)
    {
        Py_XDECREF(system);
        return 0;
    }
    
    system->patient = patient;
    Py_XINCREF(patient); // hang on to the patient until death
    return weakref;
}
Ejemplo n.º 5
0
static int
PySurface_LockBy (PyObject* surfobj, PyObject* lockobj)
{
    PyObject *ref;
    PySurfaceObject* surf = (PySurfaceObject*) surfobj;

    if (!surf->locklist)
    {
        surf->locklist = PyList_New (0);
        if (!surf->locklist)
            return 0;
    }
    ref = PyWeakref_NewRef (lockobj, NULL);
    if (!ref)
        return 0;
    if (ref == Py_None)
    {
        Py_DECREF (ref);
        return 0;
    }
    PyList_Append (surf->locklist, ref);

    if (surf->subsurface)
        PySurface_Prep (surfobj);
    if (SDL_LockSurface (surf->surf) == -1)
    {
        PyErr_SetString (PyExc_RuntimeError, "error locking surface");
        return 0;
    }
    return 1;
}
Ejemplo n.º 6
0
PyObject* make_nurse_and_patient(PyObject* nurse, PyObject* patient)
{
    if (nurse == Py_None || nurse == patient)
        return nurse;
    
    if (Py_TYPE(&life_support_type) == 0)
    {
        Py_TYPE(&life_support_type) = &PyType_Type;
        PyType_Ready(&life_support_type);
    }
    
    life_support* system = PyObject_New(life_support, &life_support_type);
    if (!system)
        return 0;

    system->patient = 0;
    
    // We're going to leak this reference, but don't worry; the
    // life_support system decrements it when the nurse dies.
    PyObject* weakref = PyWeakref_NewRef(nurse, (PyObject*)system);

    // weakref has either taken ownership, or we have to release it
    // anyway
    Py_DECREF(system);
    if (!weakref)
        return 0;
    
    system->patient = patient;
    Py_XINCREF(patient); // hang on to the patient until death
    return weakref;
}
Ejemplo n.º 7
0
int WeakSet_Contains(PyObject *self,PyObject *key){
    PyObject *ref = PyWeakref_NewRef((PyObject *)key,NULL);
    if (!ref) return -1;

    int r = PySet_Contains(((WeakSet *)self)->set,ref);
    Py_DECREF(ref);
    return r;
}
Ejemplo n.º 8
0
/*
 * Return a weak reference to the given object.
 */
static PyObject *getWeakRef(PyObject *obj)
{
    PyObject *wr;

    if ((wr = PyWeakref_NewRef(obj,NULL)) == NULL)
        PyErr_Clear();

    return wr;
}
Ejemplo n.º 9
0
static void sllistnode_link(PyObject* next,
                            SLListNodeObject* inserted,
                            PyObject* owner_list)
{
    assert(inserted != NULL);
    assert(inserted->next == Py_None);
    assert(owner_list != NULL);
    assert(owner_list != Py_None);

    if (next != NULL)
        inserted->next = next;

    Py_DECREF(inserted->list_weakref);
    inserted->list_weakref = PyWeakref_NewRef(owner_list, NULL);
}
Ejemplo n.º 10
0
PyObject *WeakSet_New(void){
    WeakSet *self;
    self = (WeakSet *)WeakSetType.tp_alloc(&WeakSetType, 0);
    self->set = self->selfref = NULL;

    self->set = PySet_New(NULL);
    if (!self->set) goto bail;

    self->selfref = PyWeakref_NewRef((PyObject *)self->set,NULL);
    if (!self->selfref) goto bail;

    return (PyObject *)self;
bail:
    Py_XDECREF(self->set);
    Py_XDECREF(self->selfref);
    Py_DECREF(self);
    return NULL;
}
Ejemplo n.º 11
0
/* Replacement for PQexec using the user-provided wait function.
 *
 * The function should be called helding the connection lock, and
 * the GIL because some Python code is expected to be called.
 *
 * If PGresult is NULL, there may have been either a libpq error
 * or an exception raised by Python code: before raising an exception
 * check if there is already one using `PyErr_Occurred()` */
PGresult *
psyco_exec_green(connectionObject *conn, const char *command)
{
    PGresult *result = NULL;

    /* Check that there is a single concurrently executing query */
    if (conn->async_cursor) {
        PyErr_SetString(ProgrammingError,
            "a single async query can be executed on the same connection");
        goto end;
    }
    /* we don't care about which cursor is executing the query, and
     * it may also be that no cursor is involved at all and this is
     * an internal query. So just store anything in the async_cursor,
     * respecting the code expecting it to be a weakref */
    if (!(conn->async_cursor = PyWeakref_NewRef((PyObject*)conn, NULL))) {
        goto end;
    }

    /* Send the query asynchronously */
    if (0 == pq_send_query(conn, command)) {
        goto end;
    }

    /* Enter the poll loop with a write. When writing is finished the poll
       implementation will set the status to ASYNC_READ without exiting the
       loop. If read is finished the status is finally set to ASYNC_DONE.
    */
    conn->async_status = ASYNC_WRITE;

    if (0 != psyco_wait(conn)) {
        psyco_clear_result_blocking(conn);
        goto end;
    }

    /* Now we can read the data without fear of blocking. */
    result = pq_get_last_result(conn);

end:
    conn->async_status = ASYNC_DONE;
    Py_CLEAR(conn->async_cursor);
    return result;
}
Ejemplo n.º 12
0
static PyObject * World_get_object_ref(PyWorld *self, PyObject * id)
{
    if (!PyString_CheckExact(id)) {
        PyErr_SetString(PyExc_TypeError, "World.get_object must be string");
        return NULL;
    }
    LocatedEntity * ent = BaseWorld::instance().getEntity(PyString_AsString(id));
    if (ent == NULL) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    PyObject * wrapper = wrapEntity(ent);
    if (wrapper == NULL) {
        return NULL;
    }
    PyObject * wrapper_ref = PyWeakref_NewRef(wrapper, NULL);
    // FIXME Have wrapEntity return a borrowed reference
    Py_DECREF(wrapper);
    return wrapper_ref;
}
Ejemplo n.º 13
0
/*
 * This function returns a NEW reference, i.e. caller must decref it in the end.
 */
PyObject* JySync_Init_PyWeakReference_From_JyWeakReference(jobject src, PyTypeObject* nonNativeSubtype)
{
	// Todo: Handle case that the native counterpart of the Java-referent is
	//       not weakly referenceable in CPython-terms.
	//       See PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))
	env(NULL);
	jobject jReferent = (*env)->CallObjectMethod(env, src, AbstractReference_get);
	PyObject* referent = JyNI_PyObject_FromJythonPyObject(jReferent);
//	jputs("Sync jython -> PyWeakRef*");
//	jputsLong((jlong) referent);
	/* Note that an extra Py_INCREF is not necessary since the conversion method
	 * returns a new reference.
	 * JyNI-note: It is okay to hold a refcount for the weakly referenced object.
	 * This will be decreffed when the Java-side GlobalRef is released.
	 */
	PyObject* result = PyWeakref_NewRef(referent, NULL);
	/* Todo: Consider how this shall work for non-heap objects.
	 */
	incWeakRefCount(AS_JY(result));
	// Todo: Support callback.
	return result;
}
Ejemplo n.º 14
0
Archivo: upb.c Proyecto: chenbk85/upb
static PyObject *PyUpb_ObjCacheGet(const void *obj, PyTypeObject *type) {
  PyObject *kv = PyUpb_StringForPointer(obj);
  PyObject *ref = PyDict_GetItem(obj_cache, kv);
  PyObject *ret;
  if (ref) {
    ret = PyWeakref_GetObject(ref);
    assert(ret != Py_None);
    Py_INCREF(ret);
  } else {
    PyUpb_ObjWrapper *wrapper = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0);
    wrapper->obj = (void*)obj;
    wrapper->weakreflist = NULL;
    ret = (PyObject*)wrapper;
    ref = PyWeakref_NewRef(ret, weakref_callback);
    assert(PyWeakref_GetObject(ref) == ret);
    assert(ref);
    PyDict_SetItem(obj_cache, kv, ref);
    PyDict_SetItem(reverse_cache, ref, kv);
  }
  assert(ret);
  Py_DECREF(kv);
  return ret;
}
Ejemplo n.º 15
0
static PyObject* sllist_appendnode(SLListObject* self, PyObject* arg)
{
    if (!PyObject_TypeCheck(arg, &SLListNodeType))
    {
        PyErr_SetString(PyExc_TypeError, "Argument must be a sllistnode");
        return NULL;
    }

    SLListNodeObject* node = (SLListNodeObject*) arg;

    if (node->list_weakref != Py_None || node->next != Py_None)
    {
        PyErr_SetString(PyExc_ValueError,
            "Argument node must not belong to a list");
        return NULL;
    }

    /* appending to empty list */
    if(self->first == Py_None)
        self->first = (PyObject*)node;
    /* setting next of last element as new node */
    else
        ((SLListNodeObject*)self->last)->next = (PyObject*)node;

    /* allways set last node to new node */
    self->last = (PyObject*)node;

    Py_DECREF(node->list_weakref);
    node->list_weakref = PyWeakref_NewRef((PyObject*) self, NULL);

    Py_INCREF((PyObject*)node);
    ++self->size;

    Py_INCREF((PyObject*)node);
    return (PyObject*)node;
}
Ejemplo n.º 16
0
// Create the slot for a callable.
PyQtSlot::PyQtSlot(PyObject *callable, const Chimera::Signature *slot_signature)
    : mfunc(0), mself(0), mself_wr(0), other(0), signature(slot_signature)
{
    sipMethodDef callable_m;

    if (sipGetMethod(callable, &callable_m))
    {
        // Save the component parts.
        mfunc = callable_m.pm_function;
        mself = callable_m.pm_self;
#if PY_MAJOR_VERSION < 3
        mclass = callable_m.pm_class;
#endif

        // Try and create a weak reference to the instance object.
        mself_wr = PyWeakref_NewRef(mself, 0);
    }
    else
    {
        // Give the slot an extra reference to keep it alive.
        Py_INCREF(callable);
        other = callable;
    }
}
Ejemplo n.º 17
0
/* Return a new reference to a Python Connection or subclass (given by cls)
 * corresponding to the DBusConnection conn, which must have been newly
 * created. For use by the Connection and Bus constructors.
 *
 * Raises AssertionError if the DBusConnection already has a Connection.
 */
static PyObject *
DBusPyConnection_NewConsumingDBusConnection(PyTypeObject *cls,
                                            DBusConnection *conn,
                                            PyObject *mainloop)
{
    Connection *self = NULL;
    PyObject *ref;
    dbus_bool_t ok;

    DBG("%s(cls=%p, conn=%p, mainloop=%p)", __func__, cls, conn, mainloop);
    DBUS_PY_RAISE_VIA_NULL_IF_FAIL(conn);

    Py_BEGIN_ALLOW_THREADS
    ref = (PyObject *)dbus_connection_get_data(conn,
                                               _connection_python_slot);
    Py_END_ALLOW_THREADS
    if (ref) {
        self = (Connection *)PyWeakref_GetObject(ref);
        ref = NULL;
        if (self && (PyObject *)self != Py_None) {
            self = NULL;
            PyErr_SetString(PyExc_AssertionError,
                            "Newly created D-Bus connection already has a "
                            "Connection instance associated with it");
            DBG("%s() fail - assertion failed, DBusPyConn has a DBusConn already", __func__);
            DBG_WHEREAMI;
            return NULL;
        }
    }
    ref = NULL;

    /* Change mainloop from a borrowed reference to an owned reference */
    if (!mainloop || mainloop == Py_None) {
        mainloop = dbus_py_get_default_main_loop();
        if (!mainloop)
            goto err;
    }
    else {
        Py_INCREF(mainloop);
    }

    DBG("Constructing Connection from DBusConnection at %p", conn);

    self = (Connection *)(cls->tp_alloc(cls, 0));
    if (!self) goto err;
    TRACE(self);

    DBG_WHEREAMI;

    self->has_mainloop = (mainloop != Py_None);
    self->conn = NULL;
    self->filters = PyList_New(0);
    if (!self->filters) goto err;
    self->object_paths = PyDict_New();
    if (!self->object_paths) goto err;

    ref = PyWeakref_NewRef((PyObject *)self, NULL);
    if (!ref) goto err;
    DBG("Created weak ref %p to (Connection *)%p for (DBusConnection *)%p",
        ref, self, conn);

    Py_BEGIN_ALLOW_THREADS
    ok = dbus_connection_set_data(conn, _connection_python_slot,
                                  (void *)ref,
                                  (DBusFreeFunction)dbus_py_take_gil_and_xdecref);
    Py_END_ALLOW_THREADS

    if (ok) {
        DBG("Attached weak ref %p ((Connection *)%p) to (DBusConnection *)%p",
            ref, self, conn);
        ref = NULL;     /* don't DECREF it - the DBusConnection owns it now */
    }
    else {
        DBG("Failed to attached weak ref %p ((Connection *)%p) to "
            "(DBusConnection *)%p - will dispose of it", ref, self, conn);
        PyErr_NoMemory();
        goto err;
    }

    DBUS_PY_RAISE_VIA_GOTO_IF_FAIL(conn, err);
    self->conn = conn;
    /* the DBusPyConnection will close it now */
    conn = NULL;

    if (self->has_mainloop
        && !dbus_py_set_up_connection((PyObject *)self, mainloop)) {
        goto err;
    }

    Py_CLEAR(mainloop);

    DBG("%s() -> %p", __func__, self);
    TRACE(self);
    return (PyObject *)self;

err:
    DBG("Failed to construct Connection from DBusConnection at %p", conn);
    Py_CLEAR(mainloop);
    Py_CLEAR(self);
    Py_CLEAR(ref);
    if (conn) {
        Py_BEGIN_ALLOW_THREADS
        dbus_connection_close(conn);
        dbus_connection_unref(conn);
        Py_END_ALLOW_THREADS
    }
    DBG("%s() fail", __func__);
    DBG_WHEREAMI;
    return NULL;
}
Ejemplo n.º 18
0
/// Helper function to get a weak reference to the given object
inline boost::python::object weak_ref(const boost::python::object& source)
{
  return boost::python::object(boost::python::handle<>(PyWeakref_NewRef(source.ptr(), NULL)));
}
Ejemplo n.º 19
0
static PySSLObject *
newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file,
	       enum py_ssl_server_or_client socket_type,
	       enum py_ssl_cert_requirements certreq,
	       enum py_ssl_version proto_version,
	       char *cacerts_file)
{
	PySSLObject *self;
	char *errstr = NULL;
	int ret;
	int verification_mode;

	self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */
	if (self == NULL)
		return NULL;
	self->peer_cert = NULL;
	self->ssl = NULL;
	self->ctx = NULL;
	self->Socket = NULL;

	/* Make sure the SSL error state is initialized */
	(void) ERR_get_state();
	ERR_clear_error();

	if ((key_file && !cert_file) || (!key_file && cert_file)) {
		errstr = ERRSTR("Both the key & certificate files "
                                "must be specified");
		goto fail;
	}

	if ((socket_type == PY_SSL_SERVER) &&
	    ((key_file == NULL) || (cert_file == NULL))) {
		errstr = ERRSTR("Both the key & certificate files "
                                "must be specified for server-side operation");
		goto fail;
	}

	PySSL_BEGIN_ALLOW_THREADS
	if (proto_version == PY_SSL_VERSION_TLS1)
		self->ctx = SSL_CTX_new(TLSv1_method()); /* Set up context */
	else if (proto_version == PY_SSL_VERSION_SSL3)
		self->ctx = SSL_CTX_new(SSLv3_method()); /* Set up context */
	else if (proto_version == PY_SSL_VERSION_SSL2)
		self->ctx = SSL_CTX_new(SSLv2_method()); /* Set up context */
	else if (proto_version == PY_SSL_VERSION_SSL23)
		self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */
	PySSL_END_ALLOW_THREADS

	if (self->ctx == NULL) {
		errstr = ERRSTR("Invalid SSL protocol variant specified.");
		goto fail;
	}

	if (certreq != PY_SSL_CERT_NONE) {
		if (cacerts_file == NULL) {
			errstr = ERRSTR("No root certificates specified for "
                                  "verification of other-side certificates.");
			goto fail;
		} else {
			PySSL_BEGIN_ALLOW_THREADS
			ret = SSL_CTX_load_verify_locations(self->ctx,
							    cacerts_file,
                                                            NULL);
			PySSL_END_ALLOW_THREADS
			if (ret != 1) {
				_setSSLError(NULL, 0, __FILE__, __LINE__);
				goto fail;
			}
		}
	}
	if (key_file) {
		PySSL_BEGIN_ALLOW_THREADS
		ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file,
						  SSL_FILETYPE_PEM);
		PySSL_END_ALLOW_THREADS
		if (ret != 1) {
			_setSSLError(NULL, ret, __FILE__, __LINE__);
			goto fail;
		}

		PySSL_BEGIN_ALLOW_THREADS
		ret = SSL_CTX_use_certificate_chain_file(self->ctx,
							 cert_file);
		PySSL_END_ALLOW_THREADS
		if (ret != 1) {
			/*
			fprintf(stderr, "ret is %d, errcode is %lu, %lu, with file \"%s\"\n",
				ret, ERR_peek_error(), ERR_peek_last_error(), cert_file);
				*/
			if (ERR_peek_last_error() != 0) {
				_setSSLError(NULL, ret, __FILE__, __LINE__);
				goto fail;
			}
		}
	}

        /* ssl compatibility */
        SSL_CTX_set_options(self->ctx, SSL_OP_ALL);

	verification_mode = SSL_VERIFY_NONE;
	if (certreq == PY_SSL_CERT_OPTIONAL)
		verification_mode = SSL_VERIFY_PEER;
	else if (certreq == PY_SSL_CERT_REQUIRED)
		verification_mode = (SSL_VERIFY_PEER |
				     SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
	SSL_CTX_set_verify(self->ctx, verification_mode,
			   NULL); /* set verify lvl */

	PySSL_BEGIN_ALLOW_THREADS
	self->ssl = SSL_new(self->ctx); /* New ssl struct */
	PySSL_END_ALLOW_THREADS
	SSL_set_fd(self->ssl, Sock->sock_fd);	/* Set the socket for SSL */

	/* If the socket is in non-blocking mode or timeout mode, set the BIO
	 * to non-blocking mode (blocking is the default)
	 */
	if (Sock->sock_timeout >= 0.0) {
		/* Set both the read and write BIO's to non-blocking mode */
		BIO_set_nbio(SSL_get_rbio(self->ssl), 1);
		BIO_set_nbio(SSL_get_wbio(self->ssl), 1);
	}

	PySSL_BEGIN_ALLOW_THREADS
	if (socket_type == PY_SSL_CLIENT)
		SSL_set_connect_state(self->ssl);
	else
		SSL_set_accept_state(self->ssl);
	PySSL_END_ALLOW_THREADS

	self->Socket = PyWeakref_NewRef((PyObject *) Sock, Py_None);
	return self;
 fail:
	if (errstr)
		PyErr_SetString(PySSLErrorObject, errstr);
	Py_DECREF(self);
	return NULL;
}
Ejemplo n.º 20
0
static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cdata,
                                   PyObject *destructor)
{
    PyObject *new_cdata, *ref = NULL, *tup = NULL, *remove_fn = NULL;
    Py_ssize_t index;
    PyObject *datalist;

    if (ffi->gc_wrefs == NULL) {
        /* initialize */
        datalist = PyList_New(0);
        if (datalist == NULL)
            return NULL;
        ffi->gc_wrefs = datalist;
        assert(ffi->gc_wrefs_freelist == NULL);
        ffi->gc_wrefs_freelist = Py_None;
        Py_INCREF(Py_None);
    }

    /* new_cdata = self.ffi.cast(typeof(cdata), cdata) */
    new_cdata = do_cast(cdata->c_type, (PyObject *)cdata);
    if (new_cdata == NULL)
        goto error;

    /* if freelist is None: */
    datalist = ffi->gc_wrefs;
    if (ffi->gc_wrefs_freelist == Py_None) {
        /* index = len(gc_wrefs) */
        index = PyList_GET_SIZE(datalist);
        /* gc_wrefs.append(None) */
        if (PyList_Append(datalist, Py_None) < 0)
            goto error;
        tup = Py_BuildValue("OOOn", ffi, destructor, cdata, index);
    }
    else {
        /* index = freelist */
        index = PyInt_AsSsize_t(ffi->gc_wrefs_freelist);
        if (index < 0)
            goto error;   /* should not occur */
        tup = PyTuple_Pack(4, ffi, destructor, cdata, ffi->gc_wrefs_freelist);
    }
    if (tup == NULL)
        goto error;

    remove_fn = PyCFunction_New(&remove_callback, tup);
    if (remove_fn == NULL)
        goto error;

    ref = PyWeakref_NewRef(new_cdata, remove_fn);
    if (ref == NULL)
        goto error;

    /* freelist = gc_wrefs[index] (which is None if we just did append(None)) */
    /* transfer ownership of 'datalist[index]' into gc_wrefs_freelist */
    Py_DECREF(ffi->gc_wrefs_freelist);
    ffi->gc_wrefs_freelist = PyList_GET_ITEM(datalist, index);
    /* gc_wrefs[index] = ref */
    /* transfer ownership of 'ref' into 'datalist[index]' */
    PyList_SET_ITEM(datalist, index, ref);
    Py_DECREF(remove_fn);
    Py_DECREF(tup);

    return new_cdata;

 error:
    Py_XDECREF(new_cdata);
    Py_XDECREF(ref);
    Py_XDECREF(tup);
    Py_XDECREF(remove_fn);
    return NULL;
}