On 11/14/2011 11:27 PM, Vincent van Ravesteijn wrote:
>
>
> Op 15 nov. 2011 03:35 schreef "Richard Heck" <rgh...@comcast.net
> <mailto:rgh...@comcast.net>> het volgende:
> >
> > On 11/14/2011 04:36 PM, Pavel Sanda wrote:
> >>
> >> Richard Heck wrote:
> >>>
> >>> Something like that may be happening. Pavel, can you produce a
> minimal set
> >>> just replicating the structure?
> >>
> >> confirming that the cause is r39599.
> >>
> >> the structure causing warning is:
> >> parent->child1
> >> parent->child2->child1
> >>
> > Weird. I'll have a look, obviously before 2.0.2. I guess we knew
> these double parent issues could cause problems....
> >
> > rh
>
> Yes, thats why I added the warning. I think I guarded for this as well.
>
> Do we clone all children when running asynchronous autosave? We shouldnt.
>
I think we probably do, because the cloning happens the same way as with
export. What I added  was a more complex cloning mechanism to fix
various other bugs. But we have always cloned the children in
Buffer::clone(). What I changed was how we do so. In particular, we
always clone the whole buffer structure: If we are cloning a child, we
still start by cloning the master buffer, since lots of things need
access to that.

The crash happens, though, with export, too, so it's not specific to
autosave. What's actually causing it, I think, is the fact that we only
clone each child once. Before, each child got cloned as many times as it
appeared in the structure. Unfortunately, I didn't account properly for
the sort of structure Pavel has.

The attached patch seems to fix the crash, by keeping a list of the
cloned Buffers in the master of the cloned set that we can then check as
we go to make sure we don't double delete. So it's doing the same sort
of work as the BufferList in the other case. Another option would be to
have some global list here. Comments welcome.

Richard

>From 4a1533560bb4a900f7352dd2bdb7f345ab7336b4 Mon Sep 17 00:00:00 2001
From: Richard Heck <rgh...@lyx.org>
Date: Tue, 15 Nov 2011 10:52:41 -0500
Subject: [PATCH] Fix crash reported by Pavel. We need some structure that
 will do the work the BufferList does in the non-cloned
 deletion case.

---
 src/Buffer.cpp |   29 ++++++++++++++++++++++++-----
 src/Buffer.h   |    2 ++
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index 625c0ff..3242683 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -400,9 +400,12 @@ Buffer::~Buffer()
 	Impl::BufferPositionMap::iterator end = d->children_positions.end();
 	for (; it != end; ++it) {
 		Buffer * child = const_cast<Buffer *>(it->first);
-		if (d->cloned_buffer_)
-			delete child;
 		// The child buffer might have been closed already.
+		if (d->cloned_buffer_) {
+			Buffer const * master = masterBuffer();
+			if (master->clone_list_.erase(child))
+				delete child;
+		}
 		else if (theBufferList().isLoaded(child))
 			theBufferList().releaseChild(this, child);
 	}
@@ -434,9 +437,25 @@ 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
+	bit = bufmap.find(masterBuffer());
+	LASSERT(bit != bufmap.end(), return 0);
+	Buffer * cloned_master = bit->second;
+
+	set<Buffer *> & clist = cloned_master->clone_list_;
+	clist.clear();
+	BufferMap::iterator it = bufmap.begin();
+	BufferMap::iterator en = bufmap.end();
+	for (; it != en; ++it)
+		clist.insert(it->second);
+
+	return cloned_buffer;
 }
 
 
diff --git a/src/Buffer.h b/src/Buffer.h
index bf2a9ea..d6f82ef 100644
--- a/src/Buffer.h
+++ b/src/Buffer.h
@@ -707,6 +707,8 @@ private:
 	Buffer(Buffer const &);
 	void operator=(Buffer const &);
 
+	/// a list of Buffers we cloned
+	mutable std::set<Buffer *> clone_list_;
 	/// Use the Pimpl idiom to hide the internals.
 	class Impl;
 	/// The pointer never changes although *pimpl_'s contents may.
-- 
1.7.4.4

Reply via email to