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
This commit is contained in:
Richard Heck 2011-11-17 17:58:22 +00:00
parent 6e15590764
commit a8d12fdd66

View File

@ -139,6 +139,10 @@ void showPrintError(string const & name)
Alert::error(_("Print document failed"), str); Alert::error(_("Print document failed"), str);
} }
/// a list of Buffers we cloned
set<Buffer *> cloned_buffer_list;
} // namespace anon } // namespace anon
@ -395,29 +399,43 @@ Buffer::~Buffer()
return; return;
} }
// loop over children if (isClone()) {
Impl::BufferPositionMap::iterator it = d->children_positions.begin(); // this is in case of recursive includes: we won't try to delete
Impl::BufferPositionMap::iterator end = d->children_positions.end(); // ourselves as a child.
for (; it != end; ++it) { cloned_buffer_list.erase(this);
Buffer * child = const_cast<Buffer *>(it->first); // loop over children
if (isClone()) Impl::BufferPositionMap::iterator it = d->children_positions.begin();
delete child; Impl::BufferPositionMap::iterator end = d->children_positions.end();
// The child buffer might have been closed already. for (; it != end; ++it) {
else if (theBufferList().isLoaded(child)) Buffer * child = const_cast<Buffer *>(it->first);
theBufferList().releaseChild(this, child); 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<Buffer *>(it->first);
if (theBufferList().isLoaded(child))
theBufferList().releaseChild(this, child);
}
if (!isClean()) { if (!isClean()) {
docstring msg = _("LyX attempted to close a document that had unsaved changes!\n"); docstring msg = _("LyX attempted to close a document that had unsaved changes!\n");
msg += emergencyWrite(); msg += emergencyWrite();
Alert::warning(_("Attempting to close changed document!"), msg); Alert::warning(_("Attempting to close changed document!"), msg);
} }
// clear references to children in macro tables // FIXME Do we really need to do this right before we delete d?
d->children_positions.clear(); // clear references to children in macro tables
d->position_to_children.clear(); d->children_positions.clear();
d->position_to_children.clear();
if (!isClone()) {
if (!d->temppath.destroyDirectory()) { if (!d->temppath.destroyDirectory()) {
Alert::warning(_("Could not remove temporary directory"), Alert::warning(_("Could not remove temporary directory"),
bformat(_("Could not remove the temporary directory %1$s"), bformat(_("Could not remove the temporary directory %1$s"),
@ -434,9 +452,20 @@ Buffer * Buffer::clone() const
{ {
BufferMap bufmap; BufferMap bufmap;
masterBuffer()->clone(bufmap); masterBuffer()->clone(bufmap);
BufferMap::iterator it = bufmap.find(this);
LASSERT(it != bufmap.end(), return 0); // make sure we got cloned
return it->second; 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;
} }