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) {
|
if(!deleting) {
|
||||||
for (const auto & it : children) {
|
for (const auto & it : children) {
|
||||||
ViewProvider* ChildViewProvider = getViewProvider(it);
|
if (auto ChildViewProvider = dynamic_cast<ViewProviderDocumentObject*>(getViewProvider(it))) {
|
||||||
if (ChildViewProvider) {
|
auto itOld = oldChildren.find(ChildViewProvider);
|
||||||
auto itOld = oldChildren.find(static_cast<ViewProviderDocumentObject*>(ChildViewProvider));
|
|
||||||
if(itOld!=oldChildren.end()) oldChildren.erase(itOld);
|
if(itOld!=oldChildren.end()) oldChildren.erase(itOld);
|
||||||
|
|
||||||
SoSeparator* childRootNode = ChildViewProvider->getRoot();
|
if (SoSeparator* childRootNode = ChildViewProvider->getRoot()) {
|
||||||
childGroup->addChild(childRootNode);
|
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 (SoSeparator* childFrontNode = ChildViewProvider->getFrontRoot()) {
|
||||||
if (frontGroup && childFrontNode)
|
if (childFrontNode == frontGroup) {
|
||||||
frontGroup->addChild(childFrontNode);
|
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 (SoSeparator* childBackNode = ChildViewProvider->getBackRoot()) {
|
||||||
if (backGroup && childBackNode)
|
if (childBackNode == backGroup) {
|
||||||
backGroup->addChild(childBackNode);
|
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
|
// cycling to all views of the document to remove the viewprovider from the viewer itself
|
||||||
for (Gui::BaseView* vIt : d->baseViews) {
|
for (Gui::BaseView* vIt : d->baseViews) {
|
||||||
|
|||||||
@@ -72,11 +72,18 @@ ViewProviderCoordinateSystem::~ViewProviderCoordinateSystem() {
|
|||||||
|
|
||||||
std::vector<App::DocumentObject*> ViewProviderCoordinateSystem::claimChildren() const
|
std::vector<App::DocumentObject*> ViewProviderCoordinateSystem::claimChildren() const
|
||||||
{
|
{
|
||||||
return static_cast<App::Origin*>( getObject() )->OriginFeatures.getValues();
|
auto obj = getObject<App::Origin>();
|
||||||
|
std::vector<App::DocumentObject*> childs = obj->OriginFeatures.getValues();
|
||||||
|
auto it = std::find(childs.begin(), childs.end(), obj);
|
||||||
|
if (it != childs.end()) {
|
||||||
|
childs.erase(it);
|
||||||
|
}
|
||||||
|
return childs;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<App::DocumentObject*> ViewProviderCoordinateSystem::claimChildren3D() const {
|
std::vector<App::DocumentObject*> ViewProviderCoordinateSystem::claimChildren3D() const
|
||||||
return claimChildren ();
|
{
|
||||||
|
return claimChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViewProviderCoordinateSystem::attach(App::DocumentObject* pcObject)
|
void ViewProviderCoordinateSystem::attach(App::DocumentObject* pcObject)
|
||||||
|
|||||||
Reference in New Issue
Block a user