bug 9418 is about a crash which happens during mathml generation after 
copying a math macro to the clipboard. The bug report shows several 
problems, which I'll address eventually, but the actual crash happens 
because Buffer::updateMacroInstances() iterates through the insets from 
begin to end. Thus, if a macro \a calls another macro \b with arguments 
(which needs to be defined before \a), and \b is no longer found for some 
reason (in this case because it was not part of the copied text), \b is 
replaced by an unknown macro without arguments, and the arguments are 
converted to other math insets. However, \a has just been updated, and an 
ArgumentProxy pointing to the (now deleted) argument of \b has just been 
created. This ArgumentProxy holds a reference to freed memory, and the fact 
that the crash does not always happen is pure luck (sometimes the memory is 
not immediately reused).

This problem would be easily avoided if one would iterate backwards through 
the macro insets (a macro can never reference another one which follows 
later), but unfortunately I failed to implement that, since I do not 
understand the DocIterator stuff well enough. I tried several versions, both 
using nextInset() and prevInset() in DocIterator::backwardInset() and 
Buffer::updateMacroInstances(), but nothing worked. The attached patcdh 
shows one failed attempt. Does anybody have a clue how to implement a 
backward inset iteration?


Georg


PS: The math macro stuff is far too complicated.
diff --git a/src/Buffer.cpp b/src/Buffer.cpp
index f9da416..1dce385 100644
--- a/src/Buffer.cpp
+++ b/src/Buffer.cpp
@@ -3404,10 +3404,10 @@ void Buffer::updateMacroInstances(UpdateType utype) const
 {
 	LYXERR(Debug::MACROS, "updateMacroInstances for "
 		<< d->filename.onlyFileName());
-	DocIterator it = doc_iterator_begin(this);
-	it.forwardInset();
-	DocIterator const end = doc_iterator_end(this);
-	for (; it != end; it.forwardInset()) {
+	DocIterator it = doc_iterator_end(this);
+	it.backwardInset();
+	DocIterator const beg = doc_iterator_begin(this);
+	for (; it != beg; it.backwardInset()) {
  		// look for MathData cells in InsetMathNest insets
 		InsetMath * minset = it.nextInset()->asInsetMath();
 		if (!minset)
@@ -3416,8 +3416,8 @@ void Buffer::updateMacroInstances(UpdateType utype) const
 		// update macro in all cells of the InsetMathNest
 		DocIterator::idx_type n = minset->nargs();
 		MacroContext mc = MacroContext(this, it);
-		for (DocIterator::idx_type i = 0; i < n; ++i) {
-			MathData & data = minset->cell(i);
+		for (DocIterator::idx_type i = n; i > 0; --i) {
+			MathData & data = minset->cell(i-1);
 			data.updateMacros(0, mc, utype);
 		}
 	}
diff --git a/src/DocIterator.cpp b/src/DocIterator.cpp
index e574115..d4bcad1 100644
--- a/src/DocIterator.cpp
+++ b/src/DocIterator.cpp
@@ -449,6 +449,28 @@ void DocIterator::backwardPos()
 }
 
 
+void DocIterator::backwardInset()
+{
+	backwardPos();
+
+	while (!empty() && !nextInset()) {
+		if (inTexted()) {
+			Paragraph const & par = paragraph();
+			pos_type & pos = top().pos();
+			if (pos > 0 && pos == top().lastpos())
+				--pos;
+			if (pos < top().lastpos()) {
+				while (pos > 0 && !par.isInset(pos))
+					--pos;
+				if (pos > 0)
+					break;
+			}
+		}
+		backwardPos();
+	}
+}
+
+
 bool DocIterator::hasPart(DocIterator const & it) const
 {
 	// it can't be a part if it is larger
diff --git a/src/DocIterator.h b/src/DocIterator.h
index 7796819..20ca8fe 100644
--- a/src/DocIterator.h
+++ b/src/DocIterator.h
@@ -202,8 +202,7 @@ public:
 	/// move backward one paragraph
 	void backwardPar();
 	/// move backward one inset
-	/// FIXME: This is not implemented!
-	//void backwardInset();
+	void backwardInset();
 
 	/// are we some 'extension' (i.e. deeper nested) of the given iterator
 	bool hasPart(DocIterator const & it) const;

Reply via email to