FreeCAD / FreeCAD

This is the official source code of FreeCAD, a free and opensource multiplatform 3D parametric modeler.
https://www.freecad.org
Other
19.78k stars 4.06k forks source link

Measurement: Segfault when selecting a sketch + a line (with Ctrl+left-click) #16794

Closed AIRCAP closed 1 month ago

AIRCAP commented 1 month ago

Is there an existing issue for this?

Problem description

Using the reproduction FCStd from #16630 : LoftAndSweeps1.FCStd.zip

Reproduction:

  1. Open LoftAndSweeps1.FCStd in freecad
  2. select Sketch1 (either in parts tree or by double clicking in 3d view)
  3. CTRL+left click a wire of Sketch2 in the 3d view

Expected outcome: Both the sketch and a single wire of the 2nd sketch are selected

Actual outcome: FreeCAD segfaults

Full version info

OS: Ubuntu 20.04.6 LTS (XFCE/xfce)
Word size of FreeCAD: 64-bit
Version: 1.1.0dev.38834 (Git)
Build type: Debug
Branch: main
Hash: 490d6c5abc41bb61fa5bf47398df142a8ac2519e
Python 3.8.10, Qt 5.12.8, Coin 4.0.0, Vtk 7.1.1, OCC 7.6.3
Locale: English/United States (en_US)
Stylesheet/Theme/QtStyle: unset/FreeCAD Classic/Qt default

Subproject(s) affected?

Core

Anything else?

This also happens when first a single wire is selected and then with shift+click in the parts tree the other sketch is selected.

It also happens when a sketch is selected and then a wire created with the Draft workbench, but the sketch has to be part of a body. if the sketch isn't part of a body the segfault doesn't happen

Program received signal SIGSEGV, Segmentation fault.
#0  /lib/x86_64-linux-gnu/libc.so.6(+0x43090) [0x7f3312b62090]
#1  0x7f32e753812e in BRep_Tool::Curve(TopoDS_Edge const&, TopLoc_Location&, double&, double&) from /usr/lib/x86_64-linux-gnu/libTKBRep.so.7+0x2e
#2  0x7f32e754a54c in BRepAdaptor_Curve::Initialize(TopoDS_Edge const&) from /usr/lib/x86_64-linux-gnu/libTKBRep.so.7+0xcc
#3  0x7f32e754b5f6 in BRepAdaptor_Curve::BRepAdaptor_Curve(TopoDS_Edge const&) from /usr/lib/x86_64-linux-gnu/libTKBRep.so.7+0x136
#4  0x7f32e87fcf42 in Measure::Measurement::length() const from ~/src/FreeCAD/main/Mod/Measure/Measure.so+0x272
#5  0x7f32e3c25869 in MeasureGui::QuickMeasure::printResult() from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x72b
#6  0x7f32e3c24c0e in MeasureGui::QuickMeasure::tryMeasureSelection() from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x38
#7  0x7f32e3c24b3d in MeasureGui::QuickMeasure::processSelection() from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x3b
#8  0x7f32e3c27f01 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (MeasureGui::QuickMeasure::*)()>::call(void (MeasureGui::QuickMeasure::*)(), MeasureGui::QuickMeasure*, void**) from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x7e
#9  0x7f32e3c27ca4 in void QtPrivate::FunctionPointer<void (MeasureGui::QuickMeasure::*)()>::call<QtPrivate::List<>, void>(void (MeasureGui::QuickMeasure::*)(), MeasureGui::QuickMeasure*, void**) from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x46
#10  0x7f32e3c27a03 in QtPrivate::QSlotObject<void (MeasureGui::QuickMeasure::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) from ~/src/FreeCAD/main/Mod/Measure/MeasureGui.so+0x84
#11  0x7f331330f328 in QMetaObject::activate(QObject*, int, int, void**) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x928
#12  0x7f331331c3ee in QTimer::timeout(QTimer::QPrivateSignal) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x3e
#13  0x7f331330fbc5 in QObject::event(QEvent*) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x1d5
#14  0x7f3313cfda66 in QApplicationPrivate::notify_helper(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5+0x86
#15  0x7f3313d070f0 in QApplication::notify(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5+0x330
#16  0x7f3317595f83 in Gui::GUIApplication::notify(QObject*, QEvent*) from ~/src/FreeCAD/main/lib/libFreeCADGui.so+0x111
#17  0x7f33132e380a in QCoreApplication::notifyInternal2(QObject*, QEvent*) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x18a
#18  0x7f331333a780 in QTimerInfoList::activateTimers() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x3d0
#19  /usr/lib/x86_64-linux-gnu/libQt5Core.so.5(+0x2de06c) [0x7f331333b06c]
#20  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(g_main_context_dispatch+0x27d) [0x7f3310f8e17d]
#21  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(+0x52400) [0x7f3310f8e400]
#22  /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0(g_main_context_iteration+0x33) [0x7f3310f8e4a3]
#23  0x7f331333b435 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x65
#24  0x7f33132e23ab in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x12b
#25  0x7f33132ea116 in QCoreApplication::exec() from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5+0x96
#26  ~/src/FreeCAD/main/lib/libFreeCADGui.so(+0x134a6ac) [0x7f331742b6ac]
#27  ~/src/FreeCAD/main/lib/libFreeCADGui.so(+0x134a9db) [0x7f331742b9db]
#28  0x7f331742bd18 in Gui::Application::runApplication() from ~/src/FreeCAD/main/lib/libFreeCADGui.so+0x22c
#29  ~/src/FreeCAD/main/bin/FreeCAD(+0x2dddc) [0x5606396dbddc]
#30  /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7f3312b43083]
#31  ~/src/FreeCAD/main/bin/FreeCAD(+0x2cfee) [0x5606396dafee]

Code of Conduct

AIRCAP commented 1 month ago

I currently have this reproduced with main and releases/FreeCAD-1-0 branches in self built debug builds, but I can't reproduce it with AppImage 1.0rc1.

Will do more testing if this is a FreeCAD issue or related to 3rd party libs on my system.

chennes commented 1 month ago

Heads-up @hlorus -- this looks to be something in Measure.

AIRCAP commented 1 month ago

1.0rc1 does not segfault, also when built from source - this must have regressed between rc1 and rc2 -- doing a git bisect atm (if only freecad was a bit quicker to compile)

AIRCAP commented 1 month ago
git bisect good
3c1b54200dc526697f500d7e5532bccfd99ffb09 is the first bad commit
commit 3c1b54200dc526697f500d7e5532bccfd99ffb09
Author: PaddleStroke <pierrelouis.boyer@gmail.com>
Date:   Tue Sep 17 09:44:58 2024 +0200

    Measure: Fix quickmeasure globalplacement.

 src/Mod/Measure/App/Measurement.cpp  | 28 ++++++++++++----------------
 src/Mod/Measure/Gui/QuickMeasure.cpp | 33 ++++++++++++++++++++++-----------
 2 files changed, 34 insertions(+), 27 deletions(-)
AIRCAP commented 1 month ago
#5  0x00007fffcc4fcf42 in Measure::Measurement::length (this=0x555557196540) at ~/src/FreeCAD/src/Mod/Measure/App/Measurement.cpp:353
353                 BRepAdaptor_Curve curve(edge);
(gdb) print edge
$1 = (const TopoDS_Edge &) @0x7fffffffc600: {<TopoDS_Shape> = {myTShape = {entity = 0x0}, myLocation = {myItems = {myNode = {entity = 0x0}}}, myOrient = TopAbs_EXTERNAL}, <No data fields>}
(gdb) list
348             for (; obj != objects.end(); ++obj, ++subEl) {
349 
350                 //  Get the length of one edge
351                 TopoDS_Shape shape = getShape(*obj, (*subEl).c_str());
352                 const TopoDS_Edge& edge = TopoDS::Edge(shape);
353                 BRepAdaptor_Curve curve(edge);
(gdb) print shape
$2 = {myTShape = {entity = 0x0}, myLocation = {myItems = {myNode = {entity = 0x0}}}, myOrient = TopAbs_EXTERNAL}
(gdb) print *subEl
$3 = "Body.Sketch."
(gdb) print *obj
$4 = (App::DocumentObject * const&) @0x555559d13700: 0x55555ab5ff50
AIRCAP commented 1 month ago
(gdb) print measureType
$10 = Measure::MeasureType::Line
AIRCAP commented 1 month ago

if i understand that tight - what happens here is apparently anything selected is passed through this quick measurement thing now, which tries to figure out how big stuff is.

now QuickMeasure::addSelectionToMeasurement() will just add everything selected in order with Measurement::addReference3D() in order

every time this is called it checks whats the type of the latest thing added - and sets the static local measurementType to that.

so in this case it first adds a Sketch - whatever that is - and then a line - which sets the type to Line

then it tries to print the length - and since the type is "line" it tries to turn all selected objects into lines and find out their length

that works for lines but not for sketches ... - cause they yield a 0 object when you turn them into their line - which causes a segfault

I don't even know where to begin how to fix this... obviously the flaw here is that there is a single static variable "measurementType" which just holds the latest type of the last added object - that can only work if it is ensured one never adds an object of a different type to the list

the proper thing here would probably be to keep a list of all the types that are selected instead of just the latest ... but then how to measure that would need to be chosen based on any possible selection (how do you measure the sum of points, meshes and maybe an infinitely sized origin plane for good measure? thats not defined)

so maybe just define a new type "Type::Multiple" or something and set measurementType to that every time addReference3D() is called but its type is not equal to what the previous type was

AIRCAP commented 1 month ago

or be lazy and just force the type to invalid ;)

AIRCAP commented 1 month ago

correction. findType actually goes through the whole list and should already report invalid if it finds different types iun the same selection.

however Sketches have ShapeType TopAbs_WIRE -- which is not in the select - case list at all

AIRCAP commented 1 month ago

it stands to reason that if something is encountered that is not in the switch list (default:) that then it should return Invalid

AIRCAP commented 1 month ago

I'm preparing a PR

luzpaz commented 1 month ago

@AIRCAP you're a beast :rocket: