diff --git a/src/App/Document.cpp b/src/App/Document.cpp index 64e3cb7a41..be0f89241f 100644 --- a/src/App/Document.cpp +++ b/src/App/Document.cpp @@ -1010,7 +1010,7 @@ bool Document::redo(int id) void Document::addOrRemovePropertyOfObject(TransactionalObject* obj, Property *prop, bool add) { - if (!prop || !obj) + if (!prop || !obj || !obj->isAttachedToDocument()) return; if(d->iUndoMode && !isPerformingTransaction() && !d->activeUndoTransaction) { if(!testStatus(Restoring) || testStatus(Importing)) { diff --git a/src/App/DynamicProperty.cpp b/src/App/DynamicProperty.cpp index 6bcc061c7c..ec545d86eb 100644 --- a/src/App/DynamicProperty.cpp +++ b/src/App/DynamicProperty.cpp @@ -215,7 +215,7 @@ bool DynamicProperty::removeDynamicProperty(const char* name) throw Base::RuntimeError("property is not dynamic"); Property *prop = it->property; GetApplication().signalRemoveDynamicProperty(*prop); - delete prop; + Property::destroy(prop); index.erase(it); return true; } diff --git a/src/App/Property.cpp b/src/App/Property.cpp index 5da9735176..cc1a37e9ef 100644 --- a/src/App/Property.cpp +++ b/src/App/Property.cpp @@ -138,8 +138,48 @@ ObjectIdentifier Property::canonicalPath(const ObjectIdentifier &p) const return p; } +static std::vector _RemovedProps; +static int _PropCleanerCounter; + +struct PropertyCleaner { + PropertyCleaner(Property *p) + : prop(p) + { + ++_PropCleanerCounter; + } + ~PropertyCleaner() { + if(--_PropCleanerCounter) + return; + bool found = false; + while(_RemovedProps.size()) { + auto p = _RemovedProps.back(); + _RemovedProps.pop_back(); + if(p != prop) + delete p; + else + found = true; + } + if(found) + _RemovedProps.push_back(prop); + } + + Property *prop; +}; + +void Property::destroy(Property *p) { + if(p) { + // Is it necessary to nullify the container? May cause crash if any + // onChanged() caller assumes a non-null container. + // + // p->setContainer(0); + + _RemovedProps.push_back(p); + } +} + void Property::touch() { + PropertyCleaner guard(this); if (father) father->onChanged(this); StatusBits.set(Touched); @@ -152,6 +192,7 @@ void Property::setReadOnly(bool readOnly) void Property::hasSetValue(void) { + PropertyCleaner guard(this); if (father) father->onChanged(this); StatusBits.set(Touched); diff --git a/src/App/Property.h b/src/App/Property.h index 8e4ff24061..07df953ffd 100644 --- a/src/App/Property.h +++ b/src/App/Property.h @@ -104,6 +104,9 @@ public: Property(); virtual ~Property(); + /// For safe deleting of a dynamic property + static void destroy(Property *p); + /** This method is used to get the size of objects * It is not meant to have the exact size, it is more or less an estimation * which runs fast! Is it two bytes or a GB?