Skip to content

Commit 3ad18c8

Browse files
sawenzelclaude
andcommitted
Drop tunables without a value and read hex and octal reserves
- glibc ignores the whole GLIBC_TUNABLES string if one entry has no value, so such entries are dropped and trigger a rewrite. - Reserves in hex (0x) or octal (leading 0) are read as glibc reads them, so a larger one is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 711a69e commit 3ad18c8

2 files changed

Lines changed: 34 additions & 7 deletions

File tree

‎Detectors/gconfig/include/SimSetup/StaticTLSReserve.h‎

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,34 +29,48 @@ namespace o2
2929
constexpr unsigned long Geant4StaticTLSReserve = 32768;
3030

3131
/// The GLIBC_TUNABLES value with a static TLS reserve of at least `reserve` bytes, or an empty string if
32-
/// `tunables` already has one. As in glibc, the last well-formed reserve counts. Other tunables are kept.
32+
/// `tunables` already has one. As in glibc, the last reserve counts and numbers may be hex (0x) or octal (0).
33+
/// Other tunables are kept; entries without a value are dropped, since glibc then ignores the whole string.
3334
inline std::string withStaticTLSReserve(const char* tunables, unsigned long reserve = Geant4StaticTLSReserve)
3435
{
3536
constexpr std::string_view name = "glibc.rtld.optional_static_tls";
3637
std::string kept;
3738
bool haveReserve = false;
39+
bool malformed = false;
3840
unsigned long current = 0;
3941
std::string_view rest = tunables ? tunables : "";
4042
while (!rest.empty()) {
4143
const auto colon = rest.find(':');
4244
const std::string_view entry = rest.substr(0, colon);
4345
rest = colon == std::string_view::npos ? std::string_view{} : rest.substr(colon + 1);
4446
const auto equal = entry.find('=');
47+
if (equal == std::string_view::npos || equal == 0) {
48+
malformed = true; // also the truncated reserve as it arrives in GRID jobs
49+
continue;
50+
}
4551
if (entry.substr(0, equal) == name) {
46-
const std::string_view value = equal == std::string_view::npos ? std::string_view{} : entry.substr(equal + 1);
52+
std::string_view value = entry.substr(equal + 1);
53+
int base = 10;
54+
if (value.size() > 2 && value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) {
55+
base = 16;
56+
value.remove_prefix(2);
57+
} else if (value.size() > 1 && value[0] == '0') {
58+
base = 8;
59+
value.remove_prefix(1);
60+
}
4761
unsigned long bytes = 0;
48-
const auto [end, ec] = std::from_chars(value.data(), value.data() + value.size(), bytes);
62+
const auto [end, ec] = std::from_chars(value.data(), value.data() + value.size(), bytes, base);
4963
if (!value.empty() && ec == std::errc() && end == value.data() + value.size()) {
5064
haveReserve = true;
5165
current = bytes;
66+
} else {
67+
haveReserve = false; // a broken last value leaves no reserve
5268
}
5369
continue; // our own entry replaces all of them
5470
}
55-
if (!entry.empty()) {
56-
kept += (kept.empty() ? "" : ":") + std::string(entry);
57-
}
71+
kept += (kept.empty() ? "" : ":") + std::string(entry);
5872
}
59-
if (haveReserve && current >= reserve) {
73+
if (!malformed && haveReserve && current >= reserve) {
6074
return {};
6175
}
6276
return std::string(name) + "=" + std::to_string(reserve) + (kept.empty() ? "" : ":" + kept);

‎Detectors/gconfig/test/testStaticTLSReserve.cxx‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,19 @@ BOOST_AUTO_TEST_CASE(sufficient_reserve_is_kept)
3535
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=32768", 32768), "");
3636
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=1048576", 32768), "");
3737
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.malloc.arena_max=4:glibc.rtld.optional_static_tls=65536", 32768), "");
38+
// glibc also takes hex and octal
39+
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=0x100000", 32768), "");
40+
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=0100000", 32768), "");
41+
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=0x200", 32768), "glibc.rtld.optional_static_tls=32768");
42+
}
43+
44+
BOOST_AUTO_TEST_CASE(malformed_entries_are_dropped)
45+
{
46+
// glibc ignores the whole string if one entry has no value, so a good reserve next to it does not count
47+
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.rtld.optional_static_tls=32768:glibc.malloc.arena_max", 32768),
48+
"glibc.rtld.optional_static_tls=32768");
49+
BOOST_CHECK_EQUAL(withStaticTLSReserve("glibc.malloc.arena_max:glibc.malloc.tcache_count=0", 32768),
50+
"glibc.rtld.optional_static_tls=32768:glibc.malloc.tcache_count=0");
3851
}
3952

4053
BOOST_AUTO_TEST_CASE(other_tunables_are_kept)

0 commit comments

Comments
 (0)