summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-07-13 02:22:03 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-07-13 02:22:03 (GMT)
commitd7472ec13a65c6c5ff00365b1477677d1fecbb3c (patch)
tree7a434cc551919130aa58974926588035e20d0c59
parent5c5fca9844a5aa7b56ca45fe324491cb2b43a7cd (diff)
downloadcpython-d7472ec13a65c6c5ff00365b1477677d1fecbb3c.zip
cpython-d7472ec13a65c6c5ff00365b1477677d1fecbb3c.tar.gz
cpython-d7472ec13a65c6c5ff00365b1477677d1fecbb3c.tar.bz2
Fixed critical shutdown race in _Database._commit.
Related to SF patch 723231 (which pointed out the problem, but didn't fix it, just shut up the warning msg -- which was pointing out a dead- serious bug!). Bugfix candidate.
-rw-r--r--Lib/dumbdbm.py24
-rw-r--r--Misc/NEWS8
2 files changed, 27 insertions, 5 deletions
diff --git a/Lib/dumbdbm.py b/Lib/dumbdbm.py
index 8e2ec90..4e426f1 100644
--- a/Lib/dumbdbm.py
+++ b/Lib/dumbdbm.py
@@ -33,6 +33,17 @@ error = IOError # For anydbm
class _Database(UserDict.DictMixin):
+ # The on-disk directory and data files can remain in mutually
+ # inconsistent states for an arbitrarily long time (see comments
+ # at the end of __setitem__). This is only repaired when _commit()
+ # gets called. One place _commit() gets called is from __del__(),
+ # and if that occurs at program shutdown time, module globals may
+ # already have gotten rebound to None. Since it's crucial that
+ # _commit() finish sucessfully, we can't ignore shutdown races
+ # here, and _commit() must not reference any globals.
+ _os = _os # for _commit()
+ _open = _open # for _commit()
+
def __init__(self, filebasename, mode):
self._mode = mode
@@ -78,17 +89,20 @@ class _Database(UserDict.DictMixin):
# file (if any) is renamed with a .bak extension first. If a .bak
# file currently exists, it's deleted.
def _commit(self):
+ # CAUTION: It's vital that _commit() succeed, and _commit() can
+ # be called from __del__(). Therefore we must never reference a
+ # global in this routine.
try:
- _os.unlink(self._bakfile)
- except _os.error:
+ self._os.unlink(self._bakfile)
+ except self._os.error:
pass
try:
- _os.rename(self._dirfile, self._bakfile)
- except _os.error:
+ self._os.rename(self._dirfile, self._bakfile)
+ except self._os.error:
pass
- f = _open(self._dirfile, 'w', self._mode)
+ f = self._open(self._dirfile, 'w', self._mode)
for key, pos_and_siz_pair in self._index.iteritems():
f.write("%r, %r\n" % (key, pos_and_siz_pair))
f.close()
diff --git a/Misc/NEWS b/Misc/NEWS
index b793a73..1098ad3 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -38,6 +38,14 @@ Extension modules
Library
-------
+- It's vital that a dumbdbm database be closed properly, else the
+ on-disk data and directory files can be left in mutually inconsistent
+ states. dumbdbm.py's _Database.__del__() method attempted to close
+ the database properly, but a shutdown race in _Database._commit()
+ could prevent this form working, so that a program trusting __del__()
+ to get the on-disk files in synch could be badly surprised. The race
+ has been repaired.
+
- The classes in threading.py are now new-style classes. That they
weren't before was an oversight.