mirror of https://github.com/python/cpython.git
Bugfix for issue3885 and 'DB.verify()' crash.
Reviewed by Nick Coghlan.
This commit is contained in:
parent
09979a137a
commit
5cd5f12a48
|
@ -573,6 +573,15 @@ def test06_Truncate(self):
|
||||||
|
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
|
||||||
|
def test07_verify(self):
|
||||||
|
# Verify bug solved in 4.7.3pre8
|
||||||
|
self.d.close()
|
||||||
|
d = db.DB(self.env)
|
||||||
|
d.verify(self.filename)
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -602,13 +611,13 @@ class BasicWithEnvTestCase(BasicTestCase):
|
||||||
|
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
|
||||||
def test07_EnvRemoveAndRename(self):
|
def test08_EnvRemoveAndRename(self):
|
||||||
if not self.env:
|
if not self.env:
|
||||||
return
|
return
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print '\n', '-=' * 30
|
print '\n', '-=' * 30
|
||||||
print "Running %s.test07_EnvRemoveAndRename..." % self.__class__.__name__
|
print "Running %s.test08_EnvRemoveAndRename..." % self.__class__.__name__
|
||||||
|
|
||||||
# can't rename or remove an open DB
|
# can't rename or remove an open DB
|
||||||
self.d.close()
|
self.d.close()
|
||||||
|
@ -619,7 +628,7 @@ def test07_EnvRemoveAndRename(self):
|
||||||
|
|
||||||
# dbremove and dbrename are in 4.1 and later
|
# dbremove and dbrename are in 4.1 and later
|
||||||
if db.version() < (4,1):
|
if db.version() < (4,1):
|
||||||
del test07_EnvRemoveAndRename
|
del test08_EnvRemoveAndRename
|
||||||
|
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
|
||||||
|
@ -720,11 +729,11 @@ def test06_Transactions(self):
|
||||||
|
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
|
||||||
def test07_TxnTruncate(self):
|
def test08_TxnTruncate(self):
|
||||||
d = self.d
|
d = self.d
|
||||||
if verbose:
|
if verbose:
|
||||||
print '\n', '-=' * 30
|
print '\n', '-=' * 30
|
||||||
print "Running %s.test07_TxnTruncate..." % self.__class__.__name__
|
print "Running %s.test08_TxnTruncate..." % self.__class__.__name__
|
||||||
|
|
||||||
d.put("abcde", "ABCDE");
|
d.put("abcde", "ABCDE");
|
||||||
txn = self.env.txn_begin()
|
txn = self.env.txn_begin()
|
||||||
|
@ -737,7 +746,7 @@ def test07_TxnTruncate(self):
|
||||||
|
|
||||||
#----------------------------------------
|
#----------------------------------------
|
||||||
|
|
||||||
def test08_TxnLateUse(self):
|
def test09_TxnLateUse(self):
|
||||||
txn = self.env.txn_begin()
|
txn = self.env.txn_begin()
|
||||||
txn.abort()
|
txn.abort()
|
||||||
try:
|
try:
|
||||||
|
@ -771,11 +780,11 @@ class BTreeRecnoTestCase(BasicTestCase):
|
||||||
dbtype = db.DB_BTREE
|
dbtype = db.DB_BTREE
|
||||||
dbsetflags = db.DB_RECNUM
|
dbsetflags = db.DB_RECNUM
|
||||||
|
|
||||||
def test07_RecnoInBTree(self):
|
def test08_RecnoInBTree(self):
|
||||||
d = self.d
|
d = self.d
|
||||||
if verbose:
|
if verbose:
|
||||||
print '\n', '-=' * 30
|
print '\n', '-=' * 30
|
||||||
print "Running %s.test07_RecnoInBTree..." % self.__class__.__name__
|
print "Running %s.test08_RecnoInBTree..." % self.__class__.__name__
|
||||||
|
|
||||||
rec = d.get(200)
|
rec = d.get(200)
|
||||||
self.assertEqual(type(rec), type(()))
|
self.assertEqual(type(rec), type(()))
|
||||||
|
@ -805,11 +814,11 @@ class BTreeRecnoWithThreadFlagTestCase(BTreeRecnoTestCase):
|
||||||
class BasicDUPTestCase(BasicTestCase):
|
class BasicDUPTestCase(BasicTestCase):
|
||||||
dbsetflags = db.DB_DUP
|
dbsetflags = db.DB_DUP
|
||||||
|
|
||||||
def test08_DuplicateKeys(self):
|
def test09_DuplicateKeys(self):
|
||||||
d = self.d
|
d = self.d
|
||||||
if verbose:
|
if verbose:
|
||||||
print '\n', '-=' * 30
|
print '\n', '-=' * 30
|
||||||
print "Running %s.test08_DuplicateKeys..." % \
|
print "Running %s.test09_DuplicateKeys..." % \
|
||||||
self.__class__.__name__
|
self.__class__.__name__
|
||||||
|
|
||||||
d.put("dup0", "before")
|
d.put("dup0", "before")
|
||||||
|
@ -878,11 +887,11 @@ def otherType(self):
|
||||||
else:
|
else:
|
||||||
return db.DB_BTREE
|
return db.DB_BTREE
|
||||||
|
|
||||||
def test09_MultiDB(self):
|
def test10_MultiDB(self):
|
||||||
d1 = self.d
|
d1 = self.d
|
||||||
if verbose:
|
if verbose:
|
||||||
print '\n', '-=' * 30
|
print '\n', '-=' * 30
|
||||||
print "Running %s.test09_MultiDB..." % self.__class__.__name__
|
print "Running %s.test10_MultiDB..." % self.__class__.__name__
|
||||||
|
|
||||||
d2 = db.DB(self.env)
|
d2 = db.DB(self.env)
|
||||||
d2.open(self.filename, "second", self.dbtype,
|
d2.open(self.filename, "second", self.dbtype,
|
||||||
|
@ -1014,9 +1023,20 @@ def setUp(self) :
|
||||||
self.obj = db.DB()
|
self.obj = db.DB()
|
||||||
|
|
||||||
class CrashAndBurn(unittest.TestCase) :
|
class CrashAndBurn(unittest.TestCase) :
|
||||||
def test01_OpenCrash(self) :
|
import sys
|
||||||
# See http://bugs.python.org/issue3307
|
if sys.version_info[:3] < (2, 4, 0):
|
||||||
self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
|
def assertTrue(self, expr, msg=None):
|
||||||
|
self.failUnless(expr,msg=msg)
|
||||||
|
|
||||||
|
#def test01_OpenCrash(self) :
|
||||||
|
# # See http://bugs.python.org/issue3307
|
||||||
|
# self.assertRaises(db.DBInvalidArgError, db.DB, None, 65535)
|
||||||
|
|
||||||
|
def test02_DBEnv_dealloc(self):
|
||||||
|
# http://bugs.python.org/issue3885
|
||||||
|
import gc
|
||||||
|
self.assertRaises(db.DBInvalidArgError, db.DBEnv, ~db.DB_RPCCLIENT)
|
||||||
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
@ -1044,7 +1064,7 @@ def test_suite():
|
||||||
suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
|
suite.addTest(unittest.makeSuite(HashMultiDBTestCase))
|
||||||
suite.addTest(unittest.makeSuite(DBEnvPrivateObject))
|
suite.addTest(unittest.makeSuite(DBEnvPrivateObject))
|
||||||
suite.addTest(unittest.makeSuite(DBPrivateObject))
|
suite.addTest(unittest.makeSuite(DBPrivateObject))
|
||||||
#suite.addTest(unittest.makeSuite(CrashAndBurn))
|
suite.addTest(unittest.makeSuite(CrashAndBurn))
|
||||||
|
|
||||||
return suite
|
return suite
|
||||||
|
|
||||||
|
|
113
Modules/_bsddb.c
113
Modules/_bsddb.c
|
@ -989,7 +989,7 @@ newDBObject(DBEnvObject* arg, int flags)
|
||||||
|
|
||||||
|
|
||||||
/* Forward declaration */
|
/* Forward declaration */
|
||||||
static PyObject *DB_close_internal(DBObject* self, int flags);
|
static PyObject *DB_close_internal(DBObject* self, int flags, int do_not_close);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
DB_dealloc(DBObject* self)
|
DB_dealloc(DBObject* self)
|
||||||
|
@ -997,8 +997,15 @@ DB_dealloc(DBObject* self)
|
||||||
PyObject *dummy;
|
PyObject *dummy;
|
||||||
|
|
||||||
if (self->db != NULL) {
|
if (self->db != NULL) {
|
||||||
dummy=DB_close_internal(self,0);
|
dummy=DB_close_internal(self, 0, 0);
|
||||||
Py_XDECREF(dummy);
|
/*
|
||||||
|
** Raising exceptions while doing
|
||||||
|
** garbage collection is a fatal error.
|
||||||
|
*/
|
||||||
|
if (dummy)
|
||||||
|
Py_DECREF(dummy);
|
||||||
|
else
|
||||||
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
if (self->in_weakreflist != NULL) {
|
if (self->in_weakreflist != NULL) {
|
||||||
PyObject_ClearWeakRefs((PyObject *) self);
|
PyObject_ClearWeakRefs((PyObject *) self);
|
||||||
|
@ -1052,8 +1059,15 @@ DBCursor_dealloc(DBCursorObject* self)
|
||||||
PyObject *dummy;
|
PyObject *dummy;
|
||||||
|
|
||||||
if (self->dbc != NULL) {
|
if (self->dbc != NULL) {
|
||||||
dummy=DBC_close_internal(self);
|
dummy=DBC_close_internal(self);
|
||||||
Py_XDECREF(dummy);
|
/*
|
||||||
|
** Raising exceptions while doing
|
||||||
|
** garbage collection is a fatal error.
|
||||||
|
*/
|
||||||
|
if (dummy)
|
||||||
|
Py_DECREF(dummy);
|
||||||
|
else
|
||||||
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
if (self->in_weakreflist != NULL) {
|
if (self->in_weakreflist != NULL) {
|
||||||
PyObject_ClearWeakRefs((PyObject *) self);
|
PyObject_ClearWeakRefs((PyObject *) self);
|
||||||
|
@ -1071,6 +1085,7 @@ newDBEnvObject(int flags)
|
||||||
if (self == NULL)
|
if (self == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
self->db_env = NULL;
|
||||||
self->closed = 1;
|
self->closed = 1;
|
||||||
self->flags = flags;
|
self->flags = flags;
|
||||||
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
|
self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
|
||||||
|
@ -1107,8 +1122,15 @@ DBEnv_dealloc(DBEnvObject* self)
|
||||||
PyObject *dummy;
|
PyObject *dummy;
|
||||||
|
|
||||||
if (self->db_env) {
|
if (self->db_env) {
|
||||||
dummy=DBEnv_close_internal(self,0);
|
dummy=DBEnv_close_internal(self, 0);
|
||||||
Py_XDECREF(dummy);
|
/*
|
||||||
|
** Raising exceptions while doing
|
||||||
|
** garbage collection is a fatal error.
|
||||||
|
*/
|
||||||
|
if (dummy)
|
||||||
|
Py_DECREF(dummy);
|
||||||
|
else
|
||||||
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_XDECREF(self->event_notifyCallback);
|
Py_XDECREF(self->event_notifyCallback);
|
||||||
|
@ -1186,8 +1208,17 @@ DBTxn_dealloc(DBTxnObject* self)
|
||||||
|
|
||||||
if (self->txn) {
|
if (self->txn) {
|
||||||
int flag_prepare = self->flag_prepare;
|
int flag_prepare = self->flag_prepare;
|
||||||
|
|
||||||
dummy=DBTxn_abort_discard_internal(self,0);
|
dummy=DBTxn_abort_discard_internal(self,0);
|
||||||
Py_XDECREF(dummy);
|
/*
|
||||||
|
** Raising exceptions while doing
|
||||||
|
** garbage collection is a fatal error.
|
||||||
|
*/
|
||||||
|
if (dummy)
|
||||||
|
Py_DECREF(dummy);
|
||||||
|
else
|
||||||
|
PyErr_Clear();
|
||||||
|
|
||||||
if (!flag_prepare) {
|
if (!flag_prepare) {
|
||||||
PyErr_Warn(PyExc_RuntimeWarning,
|
PyErr_Warn(PyExc_RuntimeWarning,
|
||||||
"DBTxn aborted in destructor. No prior commit() or abort().");
|
"DBTxn aborted in destructor. No prior commit() or abort().");
|
||||||
|
@ -1280,7 +1311,14 @@ DBSequence_dealloc(DBSequenceObject* self)
|
||||||
|
|
||||||
if (self->sequence != NULL) {
|
if (self->sequence != NULL) {
|
||||||
dummy=DBSequence_close_internal(self,0,0);
|
dummy=DBSequence_close_internal(self,0,0);
|
||||||
Py_XDECREF(dummy);
|
/*
|
||||||
|
** Raising exceptions while doing
|
||||||
|
** garbage collection is a fatal error.
|
||||||
|
*/
|
||||||
|
if (dummy)
|
||||||
|
Py_DECREF(dummy);
|
||||||
|
else
|
||||||
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->in_weakreflist != NULL) {
|
if (self->in_weakreflist != NULL) {
|
||||||
|
@ -1485,10 +1523,10 @@ DB_associate(DBObject* self, PyObject* args, PyObject* kwargs)
|
||||||
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
DB_close_internal(DBObject* self, int flags)
|
DB_close_internal(DBObject* self, int flags, int do_not_close)
|
||||||
{
|
{
|
||||||
PyObject *dummy;
|
PyObject *dummy;
|
||||||
int err;
|
int err = 0;
|
||||||
|
|
||||||
if (self->db != NULL) {
|
if (self->db != NULL) {
|
||||||
/* Can be NULL if db is not in an environment */
|
/* Can be NULL if db is not in an environment */
|
||||||
|
@ -1511,10 +1549,20 @@ DB_close_internal(DBObject* self, int flags)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MYDB_BEGIN_ALLOW_THREADS;
|
/*
|
||||||
err = self->db->close(self->db, flags);
|
** "do_not_close" is used to dispose all related objects in the
|
||||||
MYDB_END_ALLOW_THREADS;
|
** tree, without actually releasing the "root" object.
|
||||||
self->db = NULL;
|
** This is done, for example, because function calls like
|
||||||
|
** "DB.verify()" implicitly close the underlying handle. So
|
||||||
|
** the handle doesn't need to be closed, but related objects
|
||||||
|
** must be cleaned up.
|
||||||
|
*/
|
||||||
|
if (!do_not_close) {
|
||||||
|
MYDB_BEGIN_ALLOW_THREADS;
|
||||||
|
err = self->db->close(self->db, flags);
|
||||||
|
MYDB_END_ALLOW_THREADS;
|
||||||
|
self->db = NULL;
|
||||||
|
}
|
||||||
RETURN_IF_ERR();
|
RETURN_IF_ERR();
|
||||||
}
|
}
|
||||||
RETURN_NONE();
|
RETURN_NONE();
|
||||||
|
@ -1526,7 +1574,7 @@ DB_close(DBObject* self, PyObject* args)
|
||||||
int flags=0;
|
int flags=0;
|
||||||
if (!PyArg_ParseTuple(args,"|i:close", &flags))
|
if (!PyArg_ParseTuple(args,"|i:close", &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
return DB_close_internal(self,flags);
|
return DB_close_internal(self, flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2146,7 +2194,7 @@ DB_open(DBObject* self, PyObject* args, PyObject* kwargs)
|
||||||
if (makeDBError(err)) {
|
if (makeDBError(err)) {
|
||||||
PyObject *dummy;
|
PyObject *dummy;
|
||||||
|
|
||||||
dummy=DB_close_internal(self,0);
|
dummy=DB_close_internal(self, 0, 0);
|
||||||
Py_XDECREF(dummy);
|
Py_XDECREF(dummy);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2840,21 +2888,24 @@ DB_verify(DBObject* self, PyObject* args, PyObject* kwargs)
|
||||||
/* XXX(nnorwitz): it should probably be an exception if outFile
|
/* XXX(nnorwitz): it should probably be an exception if outFile
|
||||||
can't be opened. */
|
can't be opened. */
|
||||||
|
|
||||||
MYDB_BEGIN_ALLOW_THREADS;
|
|
||||||
err = self->db->verify(self->db, fileName, dbName, outFile, flags);
|
|
||||||
MYDB_END_ALLOW_THREADS;
|
|
||||||
if (outFile)
|
|
||||||
fclose(outFile);
|
|
||||||
|
|
||||||
{ /* DB.verify acts as a DB handle destructor (like close) */
|
{ /* DB.verify acts as a DB handle destructor (like close) */
|
||||||
PyObject *error;
|
PyObject *error;
|
||||||
|
|
||||||
error=DB_close_internal(self,0);
|
error=DB_close_internal(self, 0, 1);
|
||||||
if (error ) {
|
if (error ) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MYDB_BEGIN_ALLOW_THREADS;
|
||||||
|
err = self->db->verify(self->db, fileName, dbName, outFile, flags);
|
||||||
|
MYDB_END_ALLOW_THREADS;
|
||||||
|
|
||||||
|
self->db = NULL; /* Implicit close; related objects already released */
|
||||||
|
|
||||||
|
if (outFile)
|
||||||
|
fclose(outFile);
|
||||||
|
|
||||||
RETURN_IF_ERR();
|
RETURN_IF_ERR();
|
||||||
RETURN_NONE();
|
RETURN_NONE();
|
||||||
}
|
}
|
||||||
|
@ -3978,7 +4029,7 @@ DBEnv_close_internal(DBEnvObject* self, int flags)
|
||||||
Py_XDECREF(dummy);
|
Py_XDECREF(dummy);
|
||||||
}
|
}
|
||||||
while(self->children_dbs) {
|
while(self->children_dbs) {
|
||||||
dummy=DB_close_internal(self->children_dbs,0);
|
dummy=DB_close_internal(self->children_dbs, 0, 0);
|
||||||
Py_XDECREF(dummy);
|
Py_XDECREF(dummy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4003,7 +4054,7 @@ DBEnv_close(DBEnvObject* self, PyObject* args)
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|i:close", &flags))
|
if (!PyArg_ParseTuple(args, "|i:close", &flags))
|
||||||
return NULL;
|
return NULL;
|
||||||
return DBEnv_close_internal(self,flags);
|
return DBEnv_close_internal(self, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5949,7 +6000,7 @@ DBTxn_abort_discard_internal(DBTxnObject* self, int discard)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
while (self->children_dbs) {
|
while (self->children_dbs) {
|
||||||
dummy=DB_close_internal(self->children_dbs,0);
|
dummy=DB_close_internal(self->children_dbs, 0, 0);
|
||||||
Py_XDECREF(dummy);
|
Py_XDECREF(dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6030,6 +6081,14 @@ DBSequence_close_internal(DBSequenceObject* self, int flags, int do_not_close)
|
||||||
self->txn=NULL;
|
self->txn=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** "do_not_close" is used to dispose all related objects in the
|
||||||
|
** tree, without actually releasing the "root" object.
|
||||||
|
** This is done, for example, because function calls like
|
||||||
|
** "DBSequence.remove()" implicitly close the underlying handle. So
|
||||||
|
** the handle doesn't need to be closed, but related objects
|
||||||
|
** must be cleaned up.
|
||||||
|
*/
|
||||||
if (!do_not_close) {
|
if (!do_not_close) {
|
||||||
MYDB_BEGIN_ALLOW_THREADS
|
MYDB_BEGIN_ALLOW_THREADS
|
||||||
err = self->sequence->close(self->sequence, flags);
|
err = self->sequence->close(self->sequence, flags);
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
#error "eek! DBVER can't handle minor versions > 9"
|
#error "eek! DBVER can't handle minor versions > 9"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PY_BSDDB_VERSION "4.7.3pre5"
|
#define PY_BSDDB_VERSION "4.7.3pre9"
|
||||||
|
|
||||||
/* Python object definitions */
|
/* Python object definitions */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue