From 6a1481b9fde3e17f57cd23101ee4dc9319b5a6e5 Mon Sep 17 00:00:00 2001 From: Oliver Lantwin Date: Fri, 5 Jun 2026 16:08:52 +0200 Subject: [PATCH] fix(geomodel): also hide std::__format vtables/typeinfo from exports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #17 added `-Wl,--version-script={local: _ZNSt8__format*;}` which hid `_ZN…`-mangled function symbols. Local audit confirmed 0 weak `_ZN` exports per geomodel lib. But CI debug PR (ShipSoft/Geometry#29) captured a backtrace showing the crash is still in libGeoModelWrite: Program received signal SIGSEGV #0 std::__format::_Sink::_M_write(…) from libGeoModelWrite.so.6 #1 std::__format::_Formatting_scanner<…>::_M_on_chars(…) from libGeoModelWrite.so.6 #2 std::__format::_Scanner::_M_scan(…) at :3942 … #7 SHiPGeometry::CalorimeterFactory::buildStack(…) at CalorimeterFactory.cpp:184 `nm -D libGeoModelWrite.so.6 | grep __format` still shows 15 entries (all `V` vague-linkage) for vtables (`_ZTV…`), typeinfo (`_ZTI…`), and typeinfo names (`_ZTS…`) of _Sink, _Buf_sink, _Fixedbuf_sink, _Seq_sink, _Scanner, _Formatting_scanner. Those are not matched by `_ZNSt8__format*` (they start with `_ZTV`/`_ZTI`/`_ZTS`, not `_ZN`), so build_geometry's `_Seq_sink` constructor still binds its vptr to libGeoModelWrite's vtable, and the virtual call lands in libGeoModelWrite's compiled-with-different-headers `_M_write`. Broaden the version script pattern to `*NSt8__format*` so vtables, typeinfo, typeinfo names, and any future nested std::__format symbols all get localized. Bump build.number to 4. --- recipes/geomodel/build.sh | 24 ++++++++++++++++-------- recipes/geomodel/recipe.yaml | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/recipes/geomodel/build.sh b/recipes/geomodel/build.sh index 183e4da..8759c3a 100644 --- a/recipes/geomodel/build.sh +++ b/recipes/geomodel/build.sh @@ -1,15 +1,23 @@ #!/bin/bash -e -# Hide std::__format weak template instantiations from the dynamic symbol -# table of every shared library produced here. libstdc++.so does not export -# strong overrides for them, so without this script the weak duplicates baked -# into libGeoModel{Xml,Write,Read,DBManager} become the only definitions the -# dynamic linker can see, and subtle libstdcxx-devel header drift between the -# geomodel build host and downstream consumers crashes std::format users at -# runtime (ShipSoft/Geometry#26). +# Hide every std::__format symbol from the dynamic symbol table of every +# shared library produced here, including vtables, typeinfo, typeinfo names, +# and template-instantiated functions. libstdc++.so does not export strong +# overrides for them, so without this script the weak/vague-linkage copies +# baked into libGeoModel{Xml,Write,Read,DBManager} become the only definitions +# the dynamic linker can see; subtle libstdcxx-devel header drift between the +# geomodel build host and downstream consumers then crashes std::format users +# at runtime (ShipSoft/Geometry#26). +# +# The mangled namespace prefix `St8__format` matches every mangling form we +# need to hide: +# _ZNSt8__format… functions +# _ZTVNSt8__format… vtables +# _ZTINSt8__format… typeinfo +# _ZTSNSt8__format… typeinfo names cat > "${SRC_DIR}/hide-std-format.ver" <<'EOF' { - local: _ZNSt8__format*; + local: *NSt8__format*; }; EOF diff --git a/recipes/geomodel/recipe.yaml b/recipes/geomodel/recipe.yaml index 1db1079..bfa086e 100644 --- a/recipes/geomodel/recipe.yaml +++ b/recipes/geomodel/recipe.yaml @@ -10,7 +10,7 @@ source: sha256: 018c5087b70d956793d06dc040f842018eb3bedd9b2f175c6090af63ce963408 build: - number: 3 + number: 4 skip: - win script: build.sh