Page MenuHomePhabricator

Dynamic casts on registered extension classes may fail
Closed, ResolvedPublic

Description

Extension classes are registered in the Qt MetaType system with the help of the BLUEBERRY_REGISTER_EXTENSION_CLASS macro. Internally, this macro uses the Qt MetaType system to register a helper function which knows how to create an instance of a certain type and returns a void*.

All BlueBerry extension classes must inherit from QObject and when constructing a registered class via QMetaType::construct, the void* is cast to QObject* and qobject_cast calls are used to further query the inheritance hierarchy.

If, however, a dynamic_cast is used on such a QObject* pointer, the cast may fail on some systems in case of multiple inheritance scenarios. This problem occurs when registering the QtWorkbenchTweaklet which inherits both from QObject and WorkbenchTweaklet.

Event Timeline

still does not work on OSX
testing procedure:

  1. git checkout this branch
  2. new bin directory
  3. cmake generating XCode project
  4. set qmake path
  5. configure / generate
  6. building successful
  7. start MITK-build project
  8. building successful
  9. error in init ExtApp in berryWorkbench.cpp:1445

activating # 17 completed.
get service ref "org.blueberry.service.IPreferencesService" for plugin "file:///Users/hal9000/MBI/mbitestings/MITK-build/bin/plugins/Debug/liborg_blueberry_osgi.dylib" = 1 refs
get service ref "org.blueberry.service.IQtStyleManager" for plugin "file:///Users/hal9000/MBI/mbitestings/MITK-build/bin/plugins/Debug/liborg_blueberry_osgi.dylib" = 1 refs
sharedlibrary apply-load-rules all
Warning: the current language does not match this frame.
Current language: auto; currently c++
(gdb)

[3f32e8]: Merge branch 'bug-8481-custom-qobject-based-type-registry-for-extensio

Merged commits:

2011-06-12 18:38:14 Sascha Zelzer [6d188d]
Include correct header


2011-06-12 17:39:25 Sascha Zelzer [964d76]
Use a QObject based type registry, similar to QMetaType.

Avoiding the cast to and from void* (as in QMetaType) allows to keep
all RTTI information and keeps dynamic_cast invocations working.


2011-06-10 11:38:22 Sascha Zelzer [26be15]
Use a custom MetaType construct helper to cast to QObjec* before void*.

ExtApp works on OSX when using the latest CTK checkout from commontk.org

Summary:

The only change necessary to make this work actually was

https://github.com/commontk/CTK/commit/ac865fe51683a8177ae87b42cbb48d30dd78c8d9

where we tell QPluginLoader to call dlopen() with the RTLD_GLOBAL flag which makes the exported symbols (especially RTTI symbols) in the loaded library available for symbol resolution of subsequently loaded libraries.

Newer glibc versions seem to handle RTTI symbols correctly accross shared libraries with dlopen() without the RTLD_GLOBAL flag set.

We keep all the other changes merged from bug-8481-custom-qobject-based-type-registry-for-extension-classes which introduce the berry::ExtensionType class instead of using QMetaType. This avoids void* tricks, does not clutter the QMetaType registry, and does not force a copy constructor for the extension classes.

(In reply to comment #4)

... This
avoids void* tricks, does not clutter the QMetaType registry, and does not
force a copy constructor for the extension classes.

Does that mean we don't need the copy constructor anymore shown here
http://www.mitk.org/wiki/Converting%20a%20BlueBerry%20bundle%20to%20a%20CTK%20plugin ?

(In reply to comment #5)

(In reply to comment #4)

... This
avoids void* tricks, does not clutter the QMetaType registry, and does not
force a copy constructor for the extension classes.

Does that mean we don't need the copy constructor anymore shown here
http://www.mitk.org/wiki/Converting%20a%20BlueBerry%20bundle%20to%20a%20CTK%20plugin
?

In theory, yes. Please test.

I reverted the use of RTLD_GLOBAL in CTK again. It led to other subtle problems with symbol resolution.

[4742cd]: Merge branch 'bug-8481-use-qobject-cast-for-tweaklets'

  • bug-8481-use

Merged commits:

2011-06-16 12:40:59 Sascha Zelzer [6a3485]
Use RTLD_GLOBAL in dlopen() for plugins with gcc < 4.5


2011-06-15 17:19:23 Sascha Zelzer [1d6316]
Use the current CTK master in MITK superbuild.


2011-06-15 17:18:34 Sascha Zelzer [897b87]
Redesigned BlueBerry tweaklets to use qobject_cast.


2011-06-15 17:08:34 Sascha Zelzer [deba0e]
Fixed sorting algorithm in case of unmet plugin dependencies.

[0d8afa]: Merge branch 'bug-8481-custom-qobject-based-type-registry-for-extensio

Merged commits:

2011-06-19 14:44:52 Sascha Zelzer [fb4ab9]
Zero index is reserved for 'not registered'

at first sight, the problem is not solved. using gcc (Ubuntu 4.4.3-4ubuntu5) 4.4.3 on Ubuntu 10.04, SandboxApp crashes in berryImageDescriptor.cpp line 31, while loading icons for the datamanager:

29 ImageDescriptor::Pointer ImageDescriptor::CreateFromImage(void* img)
30 {
31 return Tweaklets::Get(ImageTweaklet::KEY)->CreateFromImage(img);
32 }

Call Stack:
0 berry::ImageDescriptor::CreateFromImage berryImageDescriptor.cpp 31 0x7fffe2c99142
1 berry::AbstractUICTKPlugin::ImageDescriptorFromPlugin berryAbstractUICTKPlugin.cpp 262 0x7fffe2c94719
2 berry::ViewDescriptor::GetImageDescriptor berryViewDescriptor.cpp 103 0x7fffe2dd27b4
3 ViewReference berryViewReference.cpp 50 0x7fffe2ddf723
4 berry::ViewFactory::CreateView berryViewFactory.cpp 101 0x7fffe2dd8e59
5 berry::LayoutHelper::CreateView berryLayoutHelper.cpp 153 0x7fffe2d411be
6 berry::PageLayout::CreateView berryPageLayout.cpp 357 0x7fffe2d4ed31
7 berry::PageLayout::AddView berryPageLayout.cpp 226 0x7fffe2d4db0e
8 berry::PageLayout::AddView berryPageLayout.cpp 205 0x7fffe2d4da1d
9 QmitkExtDefaultPerspective::CreateInitialLayout QmitkExtDefaultPerspective.cpp 36 0x7fffc4c5b38c
10 berry::Perspective::LoadPredefinedPersp berryPerspective.cpp 490 0x7fffe2d896cf
11 berry::Perspective::CreatePresentation berryPerspective.cpp 93 0x7fffe2d8645c
12 Perspective berryPerspective.cpp 48 0x7fffe2d858f0
13 berry::WorkbenchPage::CreatePerspective berryWorkbenchPage.cpp 1707 0x7fffe2df5f73
14 berry::WorkbenchPage::Init berryWorkbenchPage.cpp 2362 0x7fffe2dfb7a1
15 WorkbenchPage berryWorkbenchPage.cpp 730 0x7fffe2def848
16 berry::WorkbenchWindow::BusyOpenPage berryWorkbenchWindow.cpp 1172 0x7fffe2e527f2
17 berry::Workbench::BusyOpenWorkbenchWindow berryWorkbench.cpp 1519 0x7fffe2e1ba7f
18 berry::Workbench::OpenFirstTimeWindow berryWorkbench.cpp 852 0x7fffe2e19309
19 berry::WorkbenchConfigurer::OpenFirstTimeWindow berryWorkbenchConfigurer.cpp 112 0x7fffe2e2276e
20 berry::WorkbenchAdvisor::OpenWindows berryWorkbenchAdvisor.cpp 156 0x7fffe2cc8238
... <More>

If this has nothing to do with the RTTI, please open another bug.

This is something else. When switching branches, moc somehow does not recreate the moc_berryQtImageTweaklet.cpp file (I think it was names something like that). Rebuilding org_blueberry_ui_qt fixes that.

reopening this issue. there are still problems. when an object is instantiated inside the plugin dll and passed across shared object library borders, dynamic_cast`s wont work, i.e. they have different typeid`s
there are currently two related bugs: T8772 and T9117

in the first case the view class registers itself for a specific EndPlacementPlanarFigureEvent which is downcasted to a itk::EventObject. the later following dynamic_cast from this base class to "EndPlacementPlanarFigureEvent" does not work

in the second case a mitk::BoolProperty is instantiated and downcasted to a mitk::BaseProperty. Again, the reverse dynamic_cast inside the mitkCore module does not work

-> REOPEN

The mentioned bugs are not related to extension classes and the Qt MetaType system.