itk v5.0: dynamic cast in itkMacro.h fails on MacOs

Hi

I built ITK on my mac with default options (BUILD_SHARED_LIBS=ON).
compiler is : Apple clang version 11.0.0 (clang-1100.0.33.12)

I build my application(s) with:
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_EXTENSIONS OFF)
SET(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -Wno-inconsistent-missing-override -Wunreachable-code-aggressive”)

It compiles fine, but at runtime at some point I get following exception:

itk::ExceptionObject: /Users/lloyd/Code/pack/InsightToolkit-5.0.0/source/Modules/Core/Common/include/itkMacro.h:1356:
itk::ERROR: Failed dynamic cast to PKN3itk5ImageIfLj2EEE object type = Image

It is as if the itk::Image<T,3> has different type across library boundaries.
I don’t really understand it - I am more experienced on Windows and don’t have any issues there with MSVC.

The “application” is actually a (boost unit) test runner console application, which loads test suite shared libs at runtime (testsuite plugins). Before upgrading to ITK v5.0.x I did not have this issue.

Any ideas?

Thanks, Bryn

This seems like the same issue DREAM3D was having.

@dyoll We could not find the root cause of that problem, so @imikejackson worked around the problem.

I just realized something.

If I have only one testsuite plugin, the test runner can execute correctly. The error appears when I load a second plugin, which also depends on ITK.

Yes, indeed. It seems to be a similar issue.

I my case I use the itkSliceContiguousImage: https://github.com/ITISFoundation/osparc-iseg/blob/master/Thirdparty/IJ/AlternativeMemoryModels/itkSliceContiguousImage.h

The same setup works with MSVC and gcc on linux. I haven’t yet observed any issues for the main application. For the testsuites I can modify the testrunner to load a specific plugin, and let cmake call each one at a time. That should be a workaround, although I don’t like not understanding what causes the problem.

DREAM.3D (http://www.github.com/bluequartzsoftware/dream3d) has the exact same issue. We have plugins to the GUI app that some depend on ITK. The FIRST plugin that gets loaded will work correctly. All subsequent plugins that get loaded and that depend on ITK will not work. It is the casting issue.

We solved it by using the simplITKExplicit library which we liberally ripped out of SIMPLItk and now build as part of our base compilation ONLY if we are on ITK 5 and macOS. MSVC and gcc don’t need the ITKExplicit library and so we don’t compile it on those platforms.

https://github.com/BlueQuartzSoftware/SIMPL/tree/develop/Source/SimpleITKExplicit

That folder has the library. Feel free to grab those bits if you need it.

To be explicitly clear how this works (and the only we we got it to work) is the following;

Say we have 2 plugins APlug and BPlug. The dependency tree is this:

APlug->SIMPLib->ITKExplicit

BPlug->SIMPLib->ITKExplicit

You cannot just have APLug and BPlug link directly to ITKExplicit. For our project there must be an intervening common library that both APlug and BPlug link against (SIMPLib in our case).

Hope that helps.

3 Likes

When we encounter this problem before I created a mini-project to experiment with the behavior of dynamic_cast on OSX. It may be useful for running experiments understanding the problem and the current behavior:

I suspect the case where the dynamic_cast created a system log event, may now fail.

1 Like

This line:

needs to be

class ITK_TEMPLATE_EXPORT SliceContiguousImage : 

ITK_TEMPLATE_EXPORT is required for macOS. Other platforms will not have an issue resolving the symbol correctly.

1 Like

Thanks everybody for your suggestions.

ITK_TEMPLATE_EXPORT does change the error. Now I get various problems, e.g. in image iterators the region is empty:

tk::ExceptionObject: /Users/lloyd/Code/pack/InsightToolkit-5.0.0/source/Modules/Core/Common/include/itkImageConstIterator.h:210:
itk::ERROR: Region ImageRegion (0x700003943868)
Dimension: 3
Index: [0, 0, 0]
Size: [512, 512, 1]
is outside of buffered region ImageRegion (0x7f9b7e436188)
Dimension: 3
Index: [0, 0, 0]
Size: [0, 0, 0]

I will investigate further, but it seems the plugin phenomenon persists. The first loaded plugin is ok, but subsequent ones behave incorrectly. I will try the suggestion from @imikejackson.

I found a different solution:

Before I loaded the plugins like this:

dlopen(file_name.c_str(), RTLD_LOCAL | RTLD_LAZY);

Now I load the plugins like this:

dlopen(file_name.c_str(), RTLD_GLOBAL | RTLD_LAZY);

According to the documentation, when you use RTLD_LOCAL (the default):

symbols defined in this library are not made available to resolve references in subsequently loaded libraries.

BTW: I followed @matt.mccormick and use ITK_TEMPLATE_EXPORT, instead of ITK_EXPORT.

@imikejackson I believe the equivalent to RTLD_GLOBAL for QPluginLoader is: pluginLoader.setLoadHints(QLibrary::ExportExternalSymbolsHint);

2 Likes

I use Qt’s plugin loading APIs. I would have to dig into those APIs/Source to see how they load the plugin files.