fix(geomodel): hide std::__format exports via linker version script#17
Conversation
Round 2 (#16) added -fvisibility-inlines-hidden, but that flag does not touch standalone template instantiations like std::__format::__write_padded<…> — they kept being emitted as weak globals visible in the dynamic symbol table of libGeoModelXml/Write/Read/ DBManager (4 each, verified with `nm -D` on hb0f4dca_2). objcopy --localize-symbol / --strip-symbol against the produced .so files also failed to clear them (no observable change in .dynsym), so post-build patching is not viable. Pass `-Wl,--version-script=hide-std-format.ver` via CMAKE_SHARED_LINKER_FLAGS instead. The script marks every `_ZNSt8__format*` symbol as local on the linker's output, while leaving the rest of geomodel's API exported. Verified locally with a minimal `std::format` consumer: 81 weak `_ZNSt8__format` exports drops to 0 once the version script is in the link line. Build number bumped to 3 so rattler-build emits a fresh artifact.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR modifies the geomodel conda recipe build configuration to enforce C++ symbol visibility. The build script now generates a linker version script that marks ChangesSymbol Visibility Enforcement
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ShipSoft/ship-conda-recipes#17 added a linker version script hiding std::__format weak template instantiations from libGeoModelXml/Write/ Read/DBManager exports. Local symbol audit now reports 0 weak _ZNSt8__format symbols in those libraries (was 4 each on build 2), and the full test suite — including OverlapCheck — passes in this environment.
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<char>::_M_write(…) from libGeoModelWrite.so.6 #1 std::__format::_Formatting_scanner<…>::_M_on_chars(…) from libGeoModelWrite.so.6 #2 std::__format::_Scanner<char>::_M_scan(…) at <format>: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<char>, _Buf_sink, _Fixedbuf_sink, _Seq_sink<string>, _Scanner, _Formatting_scanner. Those are not matched by `_ZNSt8__format*` (they start with `_ZTV`/`_ZTI`/`_ZTS`, not `_ZN`), so build_geometry's `_Seq_sink<string>` 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.
Summary
_ZNSt8__format*symbol as local in geomodel's shared libraries, passed viaCMAKE_SHARED_LINKER_FLAGS.recipes/geomodel/recipe.yamlbuild.numberto3.Why
Round 1 (#15) rebuilt geomodel against the current conda-forge
cxx-compiler(no source change, onlybuild.number). Round 2 (#16) added-fvisibility-inlines-hidden. Neither removed the four weakstd::__format::_Sink_iter<char>template instantiations thatlibGeoModelXml,libGeoModelWrite,libGeoModelRead, andlibGeoModelDBManagerkeep exporting:libstdc++.so.6does not export strong overrides, so these weak duplicates remain the only definitions visible to the dynamic linker — and subtlelibstdcxx-develheader drift between the geomodel build host and downstream consumers crashesbuild_geometryinsideGmx2Geoon GitHub Actions (ShipSoft/Geometry#26) while passing on developer machines.-fvisibility-inlines-hiddendoesn't affect these because they're standalone template instantiations, not class member inlines;objcopy --localize-symbol/--strip-symbolon the built.sos leaves the.dynsymentries untouched (verified withreadelf -W --dyn-symsbefore/after).A linker version script applied at link time is the standard way to control DSO exports. Confirmed locally with a minimal
extern "C" std::string fmt_it(int i) { return std::format("v={}", i); }test: 81 weak_ZNSt8__formatexports drops to 0 with-Wl,--version-script={ local: _ZNSt8__format*; };. Each consumer (libGeoModelXml's own internal calls,build_geometry's own calls) keeps its translation-unit-local instantiation compiled against its own contemporaneous libstdc++ headers — no cross-library ABI dependency.Test plan
geomodel 6.27.0 hb0f4dca_3to channelshipnm -Dreports 0 weak_ZNSt8__formatexports in each oflibGeoModelXml/Write/Read/DBManager.so.6pixi run testinGeometry/passes locally, and PR build: rebuild geant4-dependent recipes against geant4 11.4 #26's GitHub Actions run goes green on ubuntu-latestSummary by CodeRabbit