From: Enrico Forestieri Date: Sat, 3 Oct 2015 15:41:25 +0000 (+0200) Subject: Fix #9490: SIGSEGV involving LyX macros --- A reproducible MWE (part II) X-Git-Tag: 2.2.0alpha1~272 X-Git-Url: https://git.lyx.org/gitweb/?a=commitdiff_plain;h=82fe5183ca494fccc745953a9771ab7423a84693;p=features.git Fix #9490: SIGSEGV involving LyX macros --- A reproducible MWE (part II) --- diff --git a/src/mathed/MathMacro.cpp b/src/mathed/MathMacro.cpp index 79011287e7..e01f7c2134 100644 --- a/src/mathed/MathMacro.cpp +++ b/src/mathed/MathMacro.cpp @@ -63,6 +63,8 @@ public: /// void setOwner(MathMacro * mathMacro) { mathMacro_ = mathMacro; } /// + MathMacro const * owner() { return mathMacro_; } + /// InsetCode lyxCode() const { return ARGUMENT_PROXY_CODE; } /// void metrics(MetricsInfo & mi, Dimension & dim) const { @@ -151,6 +153,9 @@ public: /// This needs to be called every time a copy of the owner is created /// (bug 9418). void updateChildren(MathMacro * owner); + /// Recursively update the pointers of all expanded macros + /// appearing in the arguments of the current macro + void updateNestedChildren(MathMacro * owner, InsetMathNest * ni); /// name of macro docstring name_; /// current display mode @@ -190,17 +195,46 @@ void MathMacro::Private::updateChildren(MathMacro * owner) ArgumentProxy * p = dynamic_cast(expanded_[i].nucleus()); if (p) p->setOwner(owner); + + InsetMathNest * ni = expanded_[i].nucleus()->asNestInset(); + if (ni) + updateNestedChildren(owner, ni); } - if (macro_ && lyxrc.preview == LyXRC::PREVIEW_ON) { - // As MathData::metrics() is not called when instant preview is - // on, we have to update macro_ by ourselves. In this case, we - // simply let it point to the last known good copy of MacroData. + if (macro_) { + // The macro_ pointer is updated when MathData::metrics() is + // called. However, when instant preview is on or the macro is + // not on screen, MathData::metrics() is not called and we may + // have a dangling pointer. As a safety measure, when a macro + // is copied, always let macro_ point to the backup copy of the + // MacroData structure. This backup is updated every time the + // macro is changed, so it will not become stale. macro_ = ¯oBackup_; } } +void MathMacro::Private::updateNestedChildren(MathMacro * owner, InsetMathNest * ni) +{ + for (size_t i = 0; i < ni->nargs(); ++i) { + MathData & ar = ni->cell(i); + for (size_t j = 0; j < ar.size(); ++j) { + ArgumentProxy * ap = dynamic_cast + (ar[j].nucleus()); + if (ap) { + MathMacro::Private * md = ap->owner()->d; + if (md->macro_) + md->macro_ = &md->macroBackup_; + ap->setOwner(owner); + } + InsetMathNest * imn = ar[j].nucleus()->asNestInset(); + if (imn) + updateNestedChildren(owner, imn); + } + } +} + + MathMacro::MathMacro(Buffer * buf, docstring const & name) : InsetMathNest(buf, 0), d(new Private(buf, name)) {} @@ -209,6 +243,7 @@ MathMacro::MathMacro(Buffer * buf, docstring const & name) MathMacro::MathMacro(MathMacro const & that) : InsetMathNest(that), d(new Private(*that.d)) { + setBuffer(*that.buffer_); d->updateChildren(this); }