Commit 3f0db85b authored by Tim Peters's avatar Tim Peters

Gentler treatment for issue #1350.

The Python fatal errors occur only in a debug build now.

In a release build, unghostify() raises a Python SystemError
exception if it detects insanity, and ghostify() ignores the
problem (as ZODB 3.2 did, although it looks like 3.2 ignored
the problem by mistake).  This isn't *good*, because the
system is insane.  But it can become insane only by breaking
absolute threading rules, and that "should never happen".
Unfortunately, hundreds of things can go wrong if it does
happen, and we can't detect most of them.
parent 17c89bd8
...@@ -58,10 +58,12 @@ init_strings(void) ...@@ -58,10 +58,12 @@ init_strings(void)
return 0; return 0;
} }
#ifdef Py_DEBUG
static void static void
fatal(cPersistentObject *self, const char *caller, const char *detail) fatal_1350(cPersistentObject *self, const char *caller, const char *detail)
{ {
char buf[1000]; char buf[1000];
PyOS_snprintf(buf, sizeof(buf), PyOS_snprintf(buf, sizeof(buf),
"cPersistence.c %s(): object at %p with type %.200s\n" "cPersistence.c %s(): object at %p with type %.200s\n"
"%s.\n" "%s.\n"
...@@ -72,6 +74,8 @@ fatal(cPersistentObject *self, const char *caller, const char *detail) ...@@ -72,6 +74,8 @@ fatal(cPersistentObject *self, const char *caller, const char *detail)
caller, self, self->ob_type->tp_name, detail); caller, self, self->ob_type->tp_name, detail);
Py_FatalError(buf); Py_FatalError(buf);
} }
#endif
static void ghostify(cPersistentObject*); static void ghostify(cPersistentObject*);
/* Load the state of the object, unghostifying it. Upon success, return 1. /* Load the state of the object, unghostifying it. Upon success, return 1.
...@@ -103,9 +107,16 @@ unghostify(cPersistentObject *self) ...@@ -103,9 +107,16 @@ unghostify(cPersistentObject *self)
self->state = cPersistent_UPTODATE_STATE; self->state = cPersistent_UPTODATE_STATE;
Py_DECREF(r); Py_DECREF(r);
if (self->cache && self->ring.r_next == NULL) { if (self->cache && self->ring.r_next == NULL) {
fatal(self, "unghostify", #ifdef Py_DEBUG
"is not in the cache despite that we just " fatal_1350(self, "unghostify",
"unghostified it"); "is not in the cache despite that we just "
"unghostified it");
#else
PyErr_Format(PyExc_SystemError, "object at %p with type "
"%.200s not in the cache despite that we just "
"unghostified it", self, self->ob_type->tp_name);
return -1;
#endif
} }
} }
return 1; return 1;
...@@ -153,18 +164,19 @@ ghostify(cPersistentObject *self) ...@@ -153,18 +164,19 @@ ghostify(cPersistentObject *self)
return; return;
} }
if (! self->ring.r_next) { if (self->ring.r_next == NULL) {
fatal(self, "ghostify", "claims to be in a cache but isn't"); /* There's no way to raise an error in this routine. */
#ifdef Py_DEBUG
fatal_1350(self, "ghostify", "claims to be in a cache but isn't");
#else
return;
#endif
} }
/* XXX The next comment is nonsense. */ /* If we're ghostifying an object, we better have some non-ghosts. */
/* If the cache is still active, we must unlink the object. */ assert(self->cache->non_ghost_count > 0);
if (self->ring.r_next) { self->cache->non_ghost_count--;
/* if we're ghostifying an object, we better have some non-ghosts */ ring_del(&self->ring);
assert(self->cache->non_ghost_count > 0);
self->cache->non_ghost_count--;
ring_del(&self->ring);
}
self->state = cPersistent_GHOST_STATE; self->state = cPersistent_GHOST_STATE;
dictptr = _PyObject_GetDictPtr((PyObject *)self); dictptr = _PyObject_GetDictPtr((PyObject *)self);
if (dictptr && *dictptr) { if (dictptr && *dictptr) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment