diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c index a88f01fffab..9e302bcdfc3 100644 --- a/Modules/_bsddb.c +++ b/Modules/_bsddb.c @@ -528,6 +528,7 @@ static int makeDBError(int err) PyObject *errObj = NULL; PyObject *errTuple = NULL; int exceptionRaised = 0; + unsigned int bytes_left; switch (err) { case 0: /* successful, no error */ break; @@ -535,12 +536,15 @@ static int makeDBError(int err) #if (DBVER < 41) case DB_INCOMPLETE: #if INCOMPLETE_IS_WARNING - our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); - if (_db_errmsg[0]) { + bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); + /* Ensure that bytes_left never goes negative */ + if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { + bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; + assert(bytes_left >= 0); strcat(errTxt, " -- "); - strcat(errTxt, _db_errmsg); - _db_errmsg[0] = 0; + strncat(errTxt, _db_errmsg, bytes_left); } + _db_errmsg[0] = 0; #ifdef HAVE_WARNINGS exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); #else @@ -588,12 +592,15 @@ static int makeDBError(int err) } if (errObj != NULL) { - our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); - if (_db_errmsg[0]) { + bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); + /* Ensure that bytes_left never goes negative */ + if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { + bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; + assert(bytes_left >= 0); strcat(errTxt, " -- "); - strcat(errTxt, _db_errmsg); - _db_errmsg[0] = 0; + strncat(errTxt, _db_errmsg, bytes_left); } + _db_errmsg[0] = 0; errTuple = Py_BuildValue("(is)", err, errTxt); PyErr_SetObject(errObj, errTuple); @@ -798,10 +805,12 @@ newDBObject(DBEnvObject* arg, int flags) MYDB_BEGIN_ALLOW_THREADS; err = db_create(&self->db, db_env, flags); - self->db->set_errcall(self->db, _db_errorCallback); + if (self->db != NULL) { + self->db->set_errcall(self->db, _db_errorCallback); #if (DBVER >= 33) - self->db->app_private = (void*)self; + self->db->app_private = (void*)self; #endif + } MYDB_END_ALLOW_THREADS; /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs * list so that a DBEnv can refuse to close without aborting any open