Gui: Fix stackoverflow when loading corrupted file
If an object has a link to itself it may cause a stackoverflow in several cases: * If the method claimChildren3D() returns a list containing the object of the view provider then Document::handleChildren3D() will add a SoGroup to itself as a child. This will result into a stackoverflow as soon as an action traverses the scene. * If the method claimChildren() returns a list containing the object of the view provider then DocumentItem::createNewItem() causes an infinite loop with DocumentItem::populateItem() Solution: * Inside Document::handleChildren3D() avoid to add a SoGroup to itself * In this specific case fix ViewProviderCoordinateSystem::claimChildren() to avoid a cyclic dependency Hint: Since PR 18126 FreeCAD is vulnerable for this problem. This fixes issue 19682
This commit is contained in:
@@ -2719,21 +2719,42 @@ void Document::handleChildren3D(ViewProvider* viewProvider, bool deleting)
|
||||
|
||||
if(!deleting) {
|
||||
for (const auto & it : children) {
|
||||
ViewProvider* ChildViewProvider = getViewProvider(it);
|
||||
if (ChildViewProvider) {
|
||||
auto itOld = oldChildren.find(static_cast<ViewProviderDocumentObject*>(ChildViewProvider));
|
||||
if (auto ChildViewProvider = dynamic_cast<ViewProviderDocumentObject*>(getViewProvider(it))) {
|
||||
auto itOld = oldChildren.find(ChildViewProvider);
|
||||
if(itOld!=oldChildren.end()) oldChildren.erase(itOld);
|
||||
|
||||
SoSeparator* childRootNode = ChildViewProvider->getRoot();
|
||||
childGroup->addChild(childRootNode);
|
||||
if (SoSeparator* childRootNode = ChildViewProvider->getRoot()) {
|
||||
if (childRootNode == childGroup) {
|
||||
Base::Console().warning("Document::handleChildren3D: Do not add "
|
||||
"group of '%s' to itself\n",
|
||||
it->getNameInDocument());
|
||||
}
|
||||
else if (childGroup) {
|
||||
childGroup->addChild(childRootNode);
|
||||
}
|
||||
}
|
||||
|
||||
SoSeparator* childFrontNode = ChildViewProvider->getFrontRoot();
|
||||
if (frontGroup && childFrontNode)
|
||||
frontGroup->addChild(childFrontNode);
|
||||
if (SoSeparator* childFrontNode = ChildViewProvider->getFrontRoot()) {
|
||||
if (childFrontNode == frontGroup) {
|
||||
Base::Console().warning("Document::handleChildren3D: Do not add "
|
||||
"foreground group of '%s' to itself\n",
|
||||
it->getNameInDocument());
|
||||
}
|
||||
else if (frontGroup) {
|
||||
frontGroup->addChild(childFrontNode);
|
||||
}
|
||||
}
|
||||
|
||||
SoSeparator* childBackNode = ChildViewProvider->getBackRoot();
|
||||
if (backGroup && childBackNode)
|
||||
backGroup->addChild(childBackNode);
|
||||
if (SoSeparator* childBackNode = ChildViewProvider->getBackRoot()) {
|
||||
if (childBackNode == backGroup) {
|
||||
Base::Console().warning("Document::handleChildren3D: Do not add "
|
||||
"background group of '%s' to itself\n",
|
||||
it->getNameInDocument());
|
||||
}
|
||||
else if (backGroup) {
|
||||
backGroup->addChild(childBackNode);
|
||||
}
|
||||
}
|
||||
|
||||
// cycling to all views of the document to remove the viewprovider from the viewer itself
|
||||
for (Gui::BaseView* vIt : d->baseViews) {
|
||||
|
||||
Reference in New Issue
Block a user