Volume rendering broken in latest Linux previews?

My Claude found this which seems relevant: Cannot import gmsh Python package

It also came up with all these suggestions.

:robot: The rest of this post is AI-generated content.

Concrete debugging plan (what I’d ask Murat to run)

  1. Capture a real backtrace, not just frame 0:
ulimit -c unlimited
./Slicer            # reproduce crash
coredumpctl gdb     # or: gdb ./bin/SlicerApp-real core
(gdb) bt full
(gdb) info sharedlibrary
(gdb) info proc mappings

Frame 0 alone tells us nothing about the caller; bt full will show which Slicer/VTK code fed garbage into the regex.
2. Identify which libstdc++ is actually loaded at the crash site:

cd Slicer-5.11.0-2026-05-05-linux-amd64
LD_DEBUG=libs ./Slicer 2>&1 | grep -E 'libstdc\+\+|libgcc_s' | head
ldd bin/SlicerApp-real | grep -E 'stdc\+\+|gcc_s'
strings -a $(ldd bin/SlicerApp-real | awk '/libstdc\+\+/{print $3}') \
  | grep -E '^GLIBCXX_[0-9]' | sort -V | tail
strings -a /usr/lib/x86_64-linux-gnu/libstdc++.so.6 \
  | grep -E '^GLIBCXX_[0-9]' | sort -V | tail

If those two GLIBCXX max versions differ, that’s the smoking gun.
3. Run with a clean environment to rule out conda contamination:

env -i HOME=$HOME PATH=/usr/bin:/bin DISPLAY=$DISPLAY \
    LANG=C.UTF-8 LC_ALL=C.UTF-8 \
    ./Slicer

If that fixes it, walk printenv | grep -E 'LD_|PYTHON|CONDA' to find the offending var.
4. Check the locale path (cheap and worth ruling out):

locale ; locale -a | grep -i utf
  1. Bisect the factory builds. download.slicer.org keeps weekly Linux previews; install three or four (e.g. 2026-04-01, 2026-04-15, 2026-04-28, 2026-05-05) and find the first that crashes on Murat’s box. Then git log --oneline <good_rev>..<bad_rev> on Slicer + look at Superbuild revisions of VTK/Qt for that span. (The thread does not yet identify a regressing commit, despite what the WebFetch summary claimed.)
  2. If frame 0’s bt full shows the regex string is empty / null / garbage, the bug is most likely on the Slicer side (a recent change that passes an uninitialized std::string to std::regex), not glibc. Same fix shape as the 2022 vtkSlicerVolumeRenderingLogic::CreateROINode regression in 2022-01-10.

Fix paths

  • If libstdc++ mismatch is confirmed (step 2): ship a vendored libstdc++.so.6 in Slicer-5.11/lib/ and add it to the launcher’s LD_LIBRARY_PATH ahead of system. Slicer used to do this; if it was dropped, that’s the regression. Cheapest verification: cp /usr/lib/.../libstdc++.so.6 lib/Slicer-5.11/ on the build machine, re‑run, see if the crash goes away.
  • If it’s a conda/Anaconda env pollution: add a launcher guard that scrubs LD_LIBRARY_PATH entries containing anaconda/miniconda/conda before exec, and document it.
  • If it’s a real null‑string fed into std::regex: fix the call site (bt full will name it). No glibc involvement.
  • For chir.set’s Wayland/GLX issue (separate): have Slicer’s launcher detect XDG_SESSION_TYPE=wayland + Qt5 and default QT_QPA_PLATFORM=xcb, since Slicer’s Qt5 has no working Wayland path with the VTK GL contexts.

Want me to draft the launcher patch for the Wayland default, or to scaffold a slicer-debug-libs.sh script that runs steps 1–4 in one go?

I don’t really know what to do with this.

  1. It is already clear in my case that the breaking change is around vtk9.5.1->9.6.0 commit in March. After that, slicer crashes. (this specifically: ENH: Add support for building against VTK version 9.6.0 · Slicer/Slicer@1b21266 · GitHub)
  2. I do not use conda or inject LD_LIBRARY_PATH.

The rest I have no clue.

Okay, after our discussion at the developer meeting @lassoan suggested that a workaround would be to disable surface smoothing in the volume renderer:

image

I tested and I can get the crash with the current preview build if it turn on this feature, so it does seem to be the thing that triggers the bad code path. @muratmaga can you confirm?

We also realized that the builds with the crash are actually using the new VTK version, so this is probably what triggered the underlying issue. I’ll try some of the things Claude suggested and see if I can get any more info on any underlying glibc issues.

:robot: This post was written with AI assistance.

So after some testing it looks like there’s a C++ issue that I won’t try to explain that happens on linux and has to do with the way VTK compiles by default.

Probably we can patch it with these flags when building VTK:

  ...
  CMAKE_CACHE_ARGS
    ...
    -DCMAKE_CXX_VISIBILITY_PRESET:STRING=hidden
    -DCMAKE_VISIBILITY_INLINES_HIDDEN:BOOL=ON
    -DCMAKE_SHARED_LINKER_FLAGS:STRING=-Wl,-Bsymbolic-functions
)

It would be better for VTK to be built like this by default, but we can do this as a workaround if we want.

For the very short run, just turning off the surface smoothing in volume rendering is a patch.

The underlying issue is illustrated by just running this script. Maybe we can refine this here and then file an issue in the VTK gitlab with the suggested fix.

exouser@sdp-test-volume-render:~/Downloads$ cat ~/repo.sh 
#!/usr/bin/env bash
# Reproducer: VTK 9.6 std::regex ODR exposure on Linux/ELF.
# Paste into any Linux box with g++, python3-venv, and an older g++ available.
set -euo pipefail

OLDGCC=${OLDGCC:-g++-9}            # override if g++-9 missing; try g++-11 or g++-13
if ! command -v "$OLDGCC" >/dev/null; then
  cat >&2 <<EOF
need $OLDGCC in PATH.
  Ubuntu/Debian: sudo apt-get update && sudo apt-get install -y $OLDGCC
                 (older series may need 'universe' enabled, or try OLDGCC=g++-11)
  Fedora/RHEL:   sudo dnf install -y gcc-toolset-11-gcc-c++
                 then: scl enable gcc-toolset-11 -- bash  (and re-run this script)
  Arch:          sudo pacman -S gcc11   (then OLDGCC=g++-11 $0)
override the version on the command line, e.g.:  OLDGCC=g++-11 $0
EOF
  exit 1
fi

W=$(mktemp -d); cd "$W"
echo "workdir: $W"
echo "old g++:     $($OLDGCC --version | head -1)"
echo "default g++: $(g++ --version  | head -1)"

cat > companion.cxx <<'CXX'
#include <regex>
extern "C" void companion_touch() {
  static std::regex r("(a)|(b)|(c)"); (void)r;
}
CXX

"$OLDGCC" -shared -fPIC -O2 companion.cxx -o libcompanion.so

python3 -m venv .venv && . .venv/bin/activate
pip install --quiet 'vtk>=9.6'

PYCALL='import vtk; r=vtk.vtkImageReader2(); r.ComputeInternalFileName(0); print("VTK",vtk.VTK_VERSION,"ok:",repr(r.GetInternalFileName()))'

echo; echo "=== 1. bare run ==="
python -c "$PYCALL"


echo; echo "=== 2. companion preloaded (LD_PRELOAD) ==="
err=$(mktemp)
set +e
LD_PRELOAD=$PWD/libcompanion.so python -c "$PYCALL" 2> >(tee "$err" >&2)
rc=$?
set -e
echo
if [ $rc -eq 0 ]; then
  echo ">>> RESULT: did NOT reproduce (clean exit)."
  echo ">>>         Try a wider GCC gap: OLDGCC=g++-9 (or g++-7) $0"
elif [ $rc -ge 128 ]; then
  sig=$((rc - 128)); name=$(kill -l "$sig" 2>/dev/null || echo "?")
  case "$name" in
    SEGV|ABRT|BUS|ILL|FPE)
      echo ">>> RESULT: BUG REPRODUCED."
      echo ">>>         Process killed by SIG$name (signal $sig, exit $rc)."
      if grep -q 'bad_alloc\|terminate called' "$err"; then
        echo ">>>         libstdc++ aborted from an uncaught exception (e.g. std::bad_alloc)."
        echo ">>>         This is the same ODR-drift class as the SIGSEGV seen in the field."
        echo ">>>         _Compiler is built with one layout, walked with another;"
        echo ">>>         the corrupted state can deref a bad pointer (SIGSEGV) OR request"
        echo ">>>         an absurd allocation (bad_alloc -> terminate -> SIGABRT)."
      else
        echo ">>>         Same crash class as Murat's field SIGSEGV in vtkStringFormatter."
      fi
      ;;
    *)
      echo ">>> RESULT: killed by SIG$name (signal $sig); inconclusive."
      ;;
  esac
else
  echo ">>> RESULT: exited $rc (non-zero but not a signal). Not a crash; probably a Python-level error."
fi
rm -f "$err"



echo; echo "=== 3. which library wins the _Compiler template symbol ==="
for env in "" "LD_PRELOAD=$PWD/libcompanion.so"; do
  echo "-- env: ${env:-none}"
  env $env gdb --batch -q \
    -ex 'set breakpoint pending on' \
    -ex 'b vtkImageReader2::ComputeInternalFileName' \
    -ex 'run' \
    -ex "info sym 'std::__detail::_Compiler<std::__cxx11::regex_traits<char> >::_M_alternative()'" \
    --args python -c "$PYCALL" 2>/dev/null | grep -E '^\$|in section|libcompanion|libvtk|libstdc' || true
done

Yep, disabling surface smoothing makes rendering possible.

I filed an issue on the vtk tracker here: https://gitlab.kitware.com/vtk/vtk/-/work_items/20047

@pieper Can you try uninstalling the VTK Python package that Slicer builds and instead pip install the VTK whl from PyPI? I would suspect there are some differences in how we configure and build the whl versus VTK.

@jamesobutler it should be the same either way. The script I sent uses the VTK pip package and a python that is independent to Slicer.

@pieper I asked because I was thinking about

_GLIBCXX_USE_CXX11_ABI=0

Does the issue happen in Slicer core with no extensions installed with its self-built VTK whl or does a Slicer extension install a specific VTK whl that pulls from PyPI that is using a different _GLIBCXX_USE_CXX11_ABI?

Latest VTK on PyPI only provide x86_64 whls that are manylinux_2_17 as they provide manylinux_2_28 whl for ARM64 Linux only. vtk · PyPI

I’ve checked and libQtWebEngineCore.so. contains incorrectly exported std symbols until Qt-6.6, but the problem got fixed in Qt-6.7. So, the simplest fix the crash in Slicer would be to upgrade to Qt-6.7 or higher.

It is nice if we also fix this in VTK, because that way we avoid crashes in the future when any other software component incorrectly exports symbols. The flags that were proposed above (CMAKE_CXX_VISIBILITY_PRESET, CMAKE_VISIBILITY_INLINES_HIDDEN, etc.) were already set, but Claude suggested a small, localized change that made the global std:: symbols disappear. – @Sam_Horvath or @ebrahim could you patch VTK on factory with this commit and create a nightly linux build with it to confirm the fix and test that there are no regressions?

If making a custom build today is not feasible, we could just apply this patch to Slicer/VTK and check the build tomorrow.

Here’s the correct gitlab link that I was trying to post regarding a:

Mixing old and new ABIs in the same application causes crashes in std::regex due to a known libstdc++ bug: