App: Fix crash in Transaction::addObjectChange

It can happen that TransactionFactory::createTransaction() fails to create a transaction object because an unsuitable type is passed
(like BadType) and returns a null pointer.

The calling instances (Transaction::addObjectChange, Transaction::addObjectDel, Transaction::addObjectNew, Transaction::addOrRemoveProperty)
do not check for a null pointer and thus cause a segmentation fault by dereferencing it.

To fix the issue change the above methods to explicitly handle a null pointer.

This fixes issue 21095.

Note: In this case it's caused by the class ViewProviderFace which on purpose isn't added to the type system so that its type will be BadType.
This commit is contained in:
wmayer
2025-05-02 10:56:43 +02:00
committed by Ladislav Michl
parent 60b0221402
commit 1886bcda00

View File

@@ -147,18 +147,15 @@ void Transaction::changeProperty(TransactionalObject* Obj,
auto& index = _Objects.get<1>();
auto pos = index.find(Obj);
TransactionObject* To;
if (pos != index.end()) {
To = pos->second;
auto To = pos->second;
changeFunc(To);
}
else {
To = TransactionFactory::instance().createTransaction(Obj->getTypeId());
else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) {
To->status = TransactionObject::Chn;
index.emplace(Obj, To);
changeFunc(To);
}
changeFunc(To);
}
void Transaction::renameProperty(TransactionalObject* Obj, const Property* pcProp, const char* oldName)
@@ -230,8 +227,7 @@ void Transaction::addObjectNew(TransactionalObject* Obj)
seq.relocate(seq.end(), _Objects.project<0>(pos));
}
}
else {
TransactionObject* To = TransactionFactory::instance().createTransaction(Obj->getTypeId());
else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) {
To->status = TransactionObject::New;
To->_NameInDocument = Obj->detachFromDocument();
index.emplace(Obj, To);
@@ -252,8 +248,7 @@ void Transaction::addObjectDel(const TransactionalObject* Obj)
else if (pos != index.end() && pos->second->status == TransactionObject::Chn) {
pos->second->status = TransactionObject::Del;
}
else {
TransactionObject* To = TransactionFactory::instance().createTransaction(Obj->getTypeId());
else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) {
To->status = TransactionObject::Del;
index.emplace(Obj, To);
}
@@ -264,18 +259,15 @@ void Transaction::addObjectChange(const TransactionalObject* Obj, const Property
auto& index = _Objects.get<1>();
auto pos = index.find(Obj);
TransactionObject* To;
if (pos != index.end()) {
To = pos->second;
auto To = pos->second;
To->setProperty(Prop);
}
else {
To = TransactionFactory::instance().createTransaction(Obj->getTypeId());
else if (auto To = TransactionFactory::instance().createTransaction(Obj->getTypeId())) {
To->status = TransactionObject::Chn;
index.emplace(Obj, To);
To->setProperty(Prop);
}
To->setProperty(Prop);
}
@@ -556,13 +548,12 @@ void TransactionFactory::addProducer(const Base::Type& type, Base::AbstractProdu
*/
TransactionObject* TransactionFactory::createTransaction(const Base::Type& type) const
{
std::map<Base::Type, Base::AbstractProducer*>::const_iterator it;
for (it = producers.begin(); it != producers.end(); ++it) {
if (type.isDerivedFrom(it->first)) {
return static_cast<TransactionObject*>(it->second->Produce());
for (const auto& it : producers) {
if (type.isDerivedFrom(it.first)) {
return static_cast<TransactionObject*>(it.second->Produce());
}
}
assert(0);
Base::Console().log("Cannot create transaction object from %s\n", type.getName());
return nullptr;
}