Skip to content

Commit

Permalink
Change initialization order to avoid partially constructed objects.
Browse files Browse the repository at this point in the history
This avoids having to use an internal cpython function
  • Loading branch information
jnwatson committed Aug 9, 2020
1 parent c6842fb commit 22a3724
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 37 deletions.
72 changes: 42 additions & 30 deletions lmdb/cpython.c
Expand Up @@ -861,33 +861,35 @@ make_trans(EnvObject *env, DbObject *db, TransObject *parent, int write, int buf
self = env->spare_txns;
DEBUG("found freelist txn; self=%p self->txn=%p", self, self->txn)
env->spare_txns = self->spare_next;
env->max_spare_txns++;
self->flags &= ~TRANS_SPARE;
_Py_NewReference((PyObject *)self);
UNLOCKED(rc, mdb_txn_renew(self->txn));

UNLOCKED(rc, mdb_txn_renew(self->txn));
if(rc) {
mdb_txn_abort(self->txn);
self->txn = NULL;
PyObject_Del(self);
return err_set("mdb_txn_begin", rc);
}

env->max_spare_txns++;
self->flags &= ~TRANS_SPARE;

} else {
MDB_txn *txn;
if(write && env->readonly) {
const char *msg = "Cannot start write transaction with read-only env";
return err_set(msg, EACCES);
}

flags = write ? 0 : MDB_RDONLY;
UNLOCKED(rc, mdb_txn_begin(env->env, parent_txn, flags, &txn));
if(rc) {
return err_set("mdb_txn_begin", rc);
}

if(! ((self = PyObject_New(TransObject, &PyTransaction_Type)))) {
mdb_txn_abort(txn);
return NULL;
}

flags = write ? 0 : MDB_RDONLY;
UNLOCKED(rc, mdb_txn_begin(env->env, parent_txn, flags, &self->txn));
}

if(rc) {
_Py_ForgetReference((PyObject *)self);
PyObject_Del(self);
return err_set("mdb_txn_begin", rc);
self->txn = txn;
}

OBJECT_INIT(self)
Expand Down Expand Up @@ -917,6 +919,7 @@ static PyObject *
make_cursor(DbObject *db, TransObject *trans)
{
CursorObject *self;
MDB_cursor *curs;
int rc;

if(! trans->valid) {
Expand All @@ -928,17 +931,21 @@ make_cursor(DbObject *db, TransObject *trans)
return NULL;
}

self = PyObject_New(CursorObject, &PyCursor_Type);
UNLOCKED(rc, mdb_cursor_open(trans->txn, db->dbi, &self->curs));
UNLOCKED(rc, mdb_cursor_open(trans->txn, db->dbi, &curs));
if(rc) {
_Py_ForgetReference((PyObject *)self);
PyObject_Del(self);
return err_set("mdb_cursor_open", rc);
}

self = PyObject_New(CursorObject, &PyCursor_Type);
if (!self) {
mdb_cursor_close(curs);
return NULL;
}

DEBUG("sizeof cursor = %d", (int) sizeof *self)
OBJECT_INIT(self)
LINK_CHILD(trans, self)
self->curs = curs;
self->positioned = 0;
self->key.mv_size = 0;
self->val.mv_size = 0;
Expand Down Expand Up @@ -2569,14 +2576,17 @@ static PyObject *
new_iterator(CursorObject *cursor, IterValFunc val_func, MDB_cursor_op op)
{
IterObject *iter = PyObject_New(IterObject, &PyIterator_Type);
if(iter) {
iter->val_func = val_func;
iter->curs = cursor;
Py_INCREF(cursor);
iter->started = 0;
iter->op = op;
}
DEBUG("new_iterator: %#p", (void *)iter)
if (!iter) {
return NULL;
}

iter->val_func = val_func;
iter->curs = cursor;
Py_INCREF(cursor);
iter->started = 0;
iter->op = op;

DEBUG("new_iterator: %p", (void *)iter)
return (PyObject *) iter;
}

Expand Down Expand Up @@ -2980,15 +2990,17 @@ trans_dealloc(TransObject *self)
self->spare_next = self->env->spare_txns;
self->env->spare_txns = self;
self->env->max_spare_txns--;
Py_INCREF(self);

Py_CLEAR(self->db);
UNLINK_CHILD(self->env, self)
Py_CLEAR(self->env);
} else {
MDEBUG("deleting trans")
trans_clear(self);
PyObject_Del(self);
return;
}

MDEBUG("deleting trans")
trans_clear(self);
PyObject_Del(self);
}

/**
Expand Down
1 change: 0 additions & 1 deletion tests/cursor_test.py
Expand Up @@ -31,7 +31,6 @@
from testlib import B
from testlib import BT


class ContextManagerTest(unittest.TestCase):
def tearDown(self):
testlib.cleanup()
Expand Down
2 changes: 0 additions & 2 deletions tests/env_test.py
Expand Up @@ -23,14 +23,12 @@
from __future__ import absolute_import
from __future__ import with_statement
import os
import signal
import sys
import unittest
import weakref

import testlib
from testlib import B
from testlib import BT
from testlib import OCT
from testlib import INT_TYPES
from testlib import UnicodeType
Expand Down
4 changes: 0 additions & 4 deletions tests/testlib.py
Expand Up @@ -38,7 +38,6 @@

import lmdb


_cleanups = []

def cleanup():
Expand Down Expand Up @@ -104,12 +103,9 @@ def debug_collect():
# PyPy doesn't collect objects with __del__ on first attempt.
gc.collect()


# Handle moronic Python >=3.0 <3.3.
UnicodeType = getattr(__builtin__, 'unicode', str)
BytesType = getattr(__builtin__, 'bytes', str)


try:
INT_TYPES = (int, long)
except NameError:
Expand Down

0 comments on commit 22a3724

Please sign in to comment.