From a8d12fdd66491fe4bd30da359c53aab7f62a90f5 Mon Sep 17 00:00:00 2001 From: Richard Heck Date: Thu, 17 Nov 2011 17:58:22 +0000 Subject: [PATCH] Fix crash reported by Pavel. Multiply included children would crash the destructor since we could, in some cases, end up deleting them multiple times. So we need to keep a list of the Buffers we need to delete, kind of like the BufferList. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@40205 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Buffer.cpp | 77 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index b79101de02..6f2303e609 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -139,6 +139,10 @@ void showPrintError(string const & name) Alert::error(_("Print document failed"), str); } +/// a list of Buffers we cloned +set cloned_buffer_list; + + } // namespace anon @@ -395,29 +399,43 @@ Buffer::~Buffer() return; } - // loop over children - Impl::BufferPositionMap::iterator it = d->children_positions.begin(); - Impl::BufferPositionMap::iterator end = d->children_positions.end(); - for (; it != end; ++it) { - Buffer * child = const_cast(it->first); - if (isClone()) - delete child; - // The child buffer might have been closed already. - else if (theBufferList().isLoaded(child)) - theBufferList().releaseChild(this, child); - } + if (isClone()) { + // this is in case of recursive includes: we won't try to delete + // ourselves as a child. + cloned_buffer_list.erase(this); + // loop over children + Impl::BufferPositionMap::iterator it = d->children_positions.begin(); + Impl::BufferPositionMap::iterator end = d->children_positions.end(); + for (; it != end; ++it) { + Buffer * child = const_cast(it->first); + if (cloned_buffer_list.erase(child)) + delete child; + } + // FIXME Do we really need to do this right before we delete d? + // clear references to children in macro tables + d->children_positions.clear(); + d->position_to_children.clear(); + } else { + // loop over children + Impl::BufferPositionMap::iterator it = d->children_positions.begin(); + Impl::BufferPositionMap::iterator end = d->children_positions.end(); + for (; it != end; ++it) { + Buffer * child = const_cast(it->first); + if (theBufferList().isLoaded(child)) + theBufferList().releaseChild(this, child); + } - if (!isClean()) { - docstring msg = _("LyX attempted to close a document that had unsaved changes!\n"); - msg += emergencyWrite(); - Alert::warning(_("Attempting to close changed document!"), msg); - } - - // clear references to children in macro tables - d->children_positions.clear(); - d->position_to_children.clear(); + if (!isClean()) { + docstring msg = _("LyX attempted to close a document that had unsaved changes!\n"); + msg += emergencyWrite(); + Alert::warning(_("Attempting to close changed document!"), msg); + } + + // FIXME Do we really need to do this right before we delete d? + // clear references to children in macro tables + d->children_positions.clear(); + d->position_to_children.clear(); - if (!isClone()) { if (!d->temppath.destroyDirectory()) { Alert::warning(_("Could not remove temporary directory"), bformat(_("Could not remove the temporary directory %1$s"), @@ -434,9 +452,20 @@ Buffer * Buffer::clone() const { BufferMap bufmap; masterBuffer()->clone(bufmap); - BufferMap::iterator it = bufmap.find(this); - LASSERT(it != bufmap.end(), return 0); - return it->second; + + // make sure we got cloned + BufferMap::const_iterator bit = bufmap.find(this); + LASSERT(bit != bufmap.end(), return 0); + Buffer * cloned_buffer = bit->second; + + // record the list of cloned buffers in the cloned master + cloned_buffer_list.clear(); + BufferMap::iterator it = bufmap.begin(); + BufferMap::iterator en = bufmap.end(); + for (; it != en; ++it) + cloned_buffer_list.insert(it->second); + + return cloned_buffer; }