ITK not loading NRRD files any more

Hello,

Does ITK no longer fully support NRRD files?

I’m trying to upgrade the ITK version in my application from 4.10.1 to 5.1.1. Unfortunately, the new ITK version is throwing a floating point exception when attempting to load NRRD files. The exception occurs in this routine:

I tried both GCC and ICC build of ITK 5.1.1, as well as ITK 5.2, but the problem persists. Strangely, my ITK builds are saving NRRD files successfully, but fails to load NRRD files, including the NRRD files they themselves save. As an example, the NRRD file linked below was saved by one my ITK builds, but the same ITK build fails to load it.
0.nrrd (350.2 KB)

Is anyone else seeing this issue? Any ideas as to how to resolve this error?

Thanks.

I successfully opened 0.nrrd in Slicer 4.11.20210226 which uses ITK 5.1.2, so I think this is something specific to your computer or compilation. Mixing GCC and ICC can cause problems. What is the exception message?

Thanks for looking into it. The exception message is:

SIGFPE(0x4) - Floating point exception.
[43311] at 0x00007F7E270DD443 :itk__airSanityHelper (+0x3)

Both my ITK and application are built using ICC.

The machine I’m using is an Intel(R) Xeon(R) CPU E5-2450 v2 @ 2.50GHz. Below is my CMakeCache.txt file saved by ccmake containing the build options I used.
CMakeCache.txt (177.3 KB)

I do see some options in this file about NRRD. Should I be changing them? I didn’t see them as options to change when I ran the ccmake command (even after toggling advanced options), but I can try again.

Anything else I can experiment with?

This has more to do with floating point exceptions than with NRRD format. Maybe you gave some special floating-point related compiler options to ICC? Maybe ICC has different defaults from GCC?

Thanks @dzenanz for the direction.

I have localized the issue to the source line below, which gets invoked with val set to DBL_MAX (1.79769313486231571e+308).

Based on my research so far, it seems that the NRRD IO module is expecting the _airSanityHelper() routine to return Nan or Infinity, perhaps in compliance with IEEE 754. Like you said, it also seems there must be some compiler option I can set to get ICC to comply.

The only compiler options I was using were:
–cache_dir_contents and -std=c++11 for CMAKE_CXX_FLAGS
–cache_dir_contents -std=gnu99 for CMAKE_C_FLAGS

Based on research about getting ICC to comply with the IEEE standard, I tried adding the “-fp-model precise” option to the above, but that did not help. I had also tried compiling ITK with GCC and default options, and that had the same floating point exception issue.

Do you know what the _airSanityHelper() routine expects here exactly?

Any specific compiler flags, or other ideas I can try?

Thanks.

Can you change this to be the same as CXX flags, or remove it? miscAir.c is a C file. Or perhaps set it to C99 instead of GNU99?

Hi @dzenanz,

After additional research and experimentation, I have isolated the issue to ITK’s FloatingPointExceptions class. Specifically, the itk::FloatingPointExceptions::Disable() function doesn’t disable exceptions, though the itk::FloatingPointExceptions:: HasFloatingPointExceptionsSupport() returns true.

The NRRD IO module actually attempts to disable the exceptions before calling sanity checks, here:

But it’s ineffective in my case.

To confirm, I disabled the floating point exceptions myself in my application using the fenv.h API as demonstrated here:
https://www.visitusers.org/index.php?title=Suppressing_Floating_Point_Exceptions

The exceptions then disappeared, and I was able to load the NRRD file succesfully.

Perhaps there’s a bug in the itk::FloatingPointExceptions::Disable() function?

@jcfr I think you last fiddled with floating point exceptions. Does anything in this case ring a bell?

Does PR 2612 help you?

@dzenanz, thanks for continuing to look into this.

I’m not sure if that commit will resolve the issue. Looking at the code, itk::FloatingPointExceptions::Disable() seems to end up calling the fenv.h API function fedisableexcept() with specific flags FE_DIVBYZERO and FE_INVALID. That is assuming ITK_HAS_FEENABLEEXCEPT is defined, which is true in my case (see my CMakeCache.txt file attached above).

But, as per the doc for itk::FloatingPointExceptions::Disable(), the call is supposed to disable all floating point exceptions, including FE_OVERFLOW, which seems to be one of the exceptions the NRRD IO module will cause when it does a DBL_MAX*DBL_MAX operation. So, the itk::FloatingPointExceptions::Disable() routine should call fedisableexcept() with the FE_ALL_EXCEPT flag, instead of 2 specific exception flags.

Does that make sense?

The best course of action here seems to be for you to make a PR which fixes your problem. That seems to be itk::FloatingPointExceptions::Disable() to disable all floating point exceptions?

Yep. Sure, I may have one of my teammates do the PR. We’ll keep this thread updated on the progress. Thanks for your help @dzenanz.

This PR was created and committed with the appropriate fix:

3 Likes