From b4e563a1cccd158506cca851946727a91f740af3 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Thu, 23 Apr 2026 23:09:08 +0200 Subject: [PATCH 1/6] [core] add operator < to TUUID --- core/base/inc/TUUID.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/base/inc/TUUID.h b/core/base/inc/TUUID.h index 8b691014cf5f3..10dd862f1d9de 100644 --- a/core/base/inc/TUUID.h +++ b/core/base/inc/TUUID.h @@ -100,5 +100,9 @@ inline Bool_t operator==(const TUUID &u1, const TUUID &u2) inline Bool_t operator!=(const TUUID &u1, const TUUID &u2) { return !(u1 == u2); } +inline Bool_t operator<(const TUUID &u1, const TUUID &u2) +{ + return u1.Compare(u2) == -1; +} #endif From 1d990be3debfc6c8e94aa5456e3a52df813e2901 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Thu, 23 Apr 2026 23:10:21 +0200 Subject: [PATCH 2/6] [core] add static TUUID::UUIDv4() --- core/base/inc/TUUID.h | 10 ++++++++++ core/base/src/TUUID.cxx | 24 ++++++++++++++++++++++++ core/base/test/CMakeLists.txt | 2 ++ core/base/test/UUIDTest.cxx | 22 ++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 core/base/test/UUIDTest.cxx diff --git a/core/base/inc/TUUID.h b/core/base/inc/TUUID.h index 10dd862f1d9de..c7535bcdf0c3e 100644 --- a/core/base/inc/TUUID.h +++ b/core/base/inc/TUUID.h @@ -63,11 +63,21 @@ class TUUID { void GetRandomInfo(UChar_t seed[16]); void SetFromString(const char *uuid_str); + struct TIndeterminedMarker {}; + /// Create a UUID whose content is indetermined. Used by the UUIDv4 factory method. + explicit TUUID(TIndeterminedMarker) {} + public: TUUID(); TUUID(const char *uuid_str); virtual ~TUUID(); + // Create a UUID version 4 (variant 1) UUID according to RFC 4122. + // The UUIDv4 also has 16 octets but all but the version and variant information is random. + // This leaves 122 random bits, which are filled by the system's cryptographic random number generator. + // For all intents and purposes, the resulting UUIDs are actually globally unique. + static TUUID UUIDv4(); + const char *AsString() const; Int_t Compare(const TUUID &u) const; UShort_t Hash() const; diff --git a/core/base/src/TUUID.cxx b/core/base/src/TUUID.cxx index 14bcfb648f6a5..d074bd748d15c 100644 --- a/core/base/src/TUUID.cxx +++ b/core/base/src/TUUID.cxx @@ -124,6 +124,7 @@ system clock catches up. #include "Bytes.h" #include "TVirtualMutex.h" #include "ThreadLocalStorage.h" +#include #include #include #ifdef R__WIN32 @@ -145,6 +146,29 @@ system clock catches up. #endif #include +//////////////////////////////////////////////////////////////////////////////// +/// Create a v4 UUID. + +TUUID TUUID::UUIDv4() +{ + TUUID uuid{TIndeterminedMarker()}; + + // Ensure we can treat the memory starting at uuid.fTimeLow as an array of 16 octets + assert(&uuid.fNode[5] - reinterpret_cast(&uuid.fTimeLow) + 1 == 16); + + R__ASSERT(gSystem); + const auto rv = gSystem->GetCryptoRandom(&uuid.fTimeLow, 16); + R__ASSERT(rv == 16); + // Fix up variant + uuid.fClockSeqHiAndReserved = (uuid.fClockSeqHiAndReserved & 0x3F) | (2 << 6); + // Fix up version + uuid.fTimeHiAndVersion = (uuid.fTimeHiAndVersion & 0x0FFF) | (4 << 12); + + // TODO(jblomer): we do what the default constructor does but is this still used? Can it be deprecated? + uuid.fUUIDIndex = 1 << 30; + + return uuid; +} //////////////////////////////////////////////////////////////////////////////// /// Create a UUID. diff --git a/core/base/test/CMakeLists.txt b/core/base/test/CMakeLists.txt index ecc8e6161e57b..c88591be44568 100644 --- a/core/base/test/CMakeLists.txt +++ b/core/base/test/CMakeLists.txt @@ -49,3 +49,5 @@ endif() configure_file(Foo.C Foo.C COPYONLY) ROOT_ADD_GTEST(IncludePathTest IncludePathTest.cxx LIBRARIES Core) + +ROOT_ADD_GTEST(UUIDTest UUIDTest.cxx LIBRARIES Core) diff --git a/core/base/test/UUIDTest.cxx b/core/base/test/UUIDTest.cxx new file mode 100644 index 0000000000000..dea3700052bac --- /dev/null +++ b/core/base/test/UUIDTest.cxx @@ -0,0 +1,22 @@ +#include "gtest/gtest.h" + +#include "TUUID.h" + +#include +#include + +TEST(TUUID, UUIDv4) +{ + std::set uuids; + for (int i = 0; i < 10000; ++i) { + uuids.insert(TUUID::UUIDv4()); + } + EXPECT_EQ(10000u, uuids.size()); + + TUUID u; + EXPECT_EQ('1', u.AsString()[14]); + u = TUUID::UUIDv4(); + std::string str = u.AsString(); + EXPECT_EQ('4', str[14]); + EXPECT_TRUE(str[19] == '8' || str[19] == '9' || str[19] == 'a' || str[19] == 'b'); +} From 6fc6ab160e1b0d2e2f4f49f92902035162ec9edc Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Thu, 23 Apr 2026 23:05:27 +0200 Subject: [PATCH 3/6] [core] fix race in TUUID::AsString() --- core/base/src/TUUID.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/base/src/TUUID.cxx b/core/base/src/TUUID.cxx index d074bd748d15c..61b1f711fe099 100644 --- a/core/base/src/TUUID.cxx +++ b/core/base/src/TUUID.cxx @@ -593,7 +593,7 @@ void TUUID::Print() const const char *TUUID::AsString() const { - static char uuid[40]; + TTHREAD_TLS(char) uuid[40]; snprintf(uuid,40, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", fTimeLow, fTimeMid, fTimeHiAndVersion, fClockSeqHiAndReserved, From f17534b6271c9689eb85c1dd00c1a02dc5f84e0e Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Fri, 24 Apr 2026 00:04:23 +0200 Subject: [PATCH 4/6] [io] use UUIDv4 in ROOT files Use UUIDv4 in TDirectory (hence in TDirectoryFile and TFile) and in the RMiniFile. Note that TDirectory is used without gSystem (needed for GetCryptoRandom()) in the context of rootcling. In principle, GetCryptoRandom() should work without a TSystem object. That may be for a later commit. The UUIDv4, unlike the current UUIDv1, is (with high enough probability) globally unique. --- core/base/src/TDirectory.cxx | 8 ++++++++ io/io/test/TFileTests.cxx | 5 +++++ tree/ntuple/src/RMiniFile.cxx | 2 +- tree/ntuple/test/ntuple_minifile.cxx | 1 + 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/base/src/TDirectory.cxx b/core/base/src/TDirectory.cxx index 136a7cb5b7ff2..75340e1e6366c 100644 --- a/core/base/src/TDirectory.cxx +++ b/core/base/src/TDirectory.cxx @@ -52,6 +52,10 @@ Describe directory structure in memory. TDirectory::TDirectory() : TNamed() { + // In the context of rootcling, we don't have gSystem + if (gSystem) + fUUID = TUUID::UUIDv4(); + // MSVC doesn't support fSpinLock=ATOMIC_FLAG_INIT; in the class definition std::atomic_flag_clear( &fSpinLock ); } @@ -72,6 +76,10 @@ TDirectory::TDirectory() : TNamed() TDirectory::TDirectory(const char *name, const char *title, Option_t * /*classname*/, TDirectory* initMotherDir) : TNamed(name, title) { + // In the context of rootcling, we don't have gSystem + if (gSystem) + fUUID = TUUID::UUIDv4(); + // MSVC doesn't support fSpinLock=ATOMIC_FLAG_INIT; in the class definition std::atomic_flag_clear( &fSpinLock ); diff --git a/io/io/test/TFileTests.cxx b/io/io/test/TFileTests.cxx index 20dc74fb6b2e4..5ef2ed684feee 100644 --- a/io/io/test/TFileTests.cxx +++ b/io/io/test/TFileTests.cxx @@ -327,3 +327,8 @@ TEST(TFile, PersistTObjectStdArray) gSystem->Unlink(filename); } +TEST(TFile, UUID) +{ + TMemFile f("uuidtest.root", "RECREATE"); + EXPECT_EQ('4', f.GetUUID().AsString()[14]); +} diff --git a/tree/ntuple/src/RMiniFile.cxx b/tree/ntuple/src/RMiniFile.cxx index be81fde06569a..ce71ec7e203a6 100644 --- a/tree/ntuple/src/RMiniFile.cxx +++ b/tree/ntuple/src/RMiniFile.cxx @@ -531,7 +531,7 @@ struct RTFUUID { RTFUUID() { - TUUID uuid; + TUUID uuid{TUUID::UUIDv4()}; char *buffer = reinterpret_cast(this); uuid.FillBuffer(buffer); assert(reinterpret_cast(buffer) <= (this + 1)); diff --git a/tree/ntuple/test/ntuple_minifile.cxx b/tree/ntuple/test/ntuple_minifile.cxx index 56e1b427f6edc..6dd2ab7ef4c70 100644 --- a/tree/ntuple/test/ntuple_minifile.cxx +++ b/tree/ntuple/test/ntuple_minifile.cxx @@ -828,6 +828,7 @@ TEST(MiniFile, UUID) TUUID uuid; uuid.SetUUID("00000000-0000-0000-0000-000000000000"); EXPECT_NE(uuid, f->GetUUID()); + EXPECT_EQ('4', f->GetUUID().AsString()[14]); } TEST(MiniFile, FreeSlots) From 1a5ac9a2ffb2fef9ce350276c14adf12f38bb9a9 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Fri, 24 Apr 2026 10:13:09 +0200 Subject: [PATCH 5/6] [core] make TSystem::GetCryptoRandom() static Factor out calling the OS crypto random number generator into a free function in the Base package. In turn, TSystem::GetCryptoRandom() can be static and does not rely in gSystem being initialized. --- core/base/CMakeLists.txt | 69 ++++++++++++++++++++++++++++ core/base/inc/ROOT/RCryptoRandom.hxx | 27 +++++++++++ core/base/inc/TSystem.h | 2 +- core/base/src/RCryptoRandom.cxx | 44 ++++++++++++++++++ core/base/src/TSystem.cxx | 10 ++-- core/base/test/CMakeLists.txt | 2 + core/base/test/CryptoRandomTest.cxx | 39 ++++++++++++++++ core/base/test/TSystemTests.cxx | 40 ---------------- core/unix/CMakeLists.txt | 64 -------------------------- core/unix/inc/TUnixSystem.h | 1 - core/unix/src/TUnixSystem.cxx | 32 ++----------- core/winnt/inc/TWinNTSystem.h | 1 - core/winnt/src/TWinNTSystem.cxx | 15 +----- 13 files changed, 195 insertions(+), 151 deletions(-) create mode 100644 core/base/inc/ROOT/RCryptoRandom.hxx create mode 100644 core/base/src/RCryptoRandom.cxx create mode 100644 core/base/test/CryptoRandomTest.cxx diff --git a/core/base/CMakeLists.txt b/core/base/CMakeLists.txt index 0ce55d1ff4a27..c78f15eed82d1 100644 --- a/core/base/CMakeLists.txt +++ b/core/base/CMakeLists.txt @@ -16,6 +16,7 @@ if(MSVC AND MSVC_VERSION GREATER_EQUAL 1925 AND MSVC_VERSION LESS 1929) endif() set(BASE_HEADERS + ROOT/RCryptoRandom.hxx ROOT/RFloat16.hxx ROOT/TErrorDefaultHandler.hxx ROOT/TExecutorCRTP.hxx @@ -118,6 +119,7 @@ set(BASE_HEADERS set(BASE_SOURCES src/Match.cxx + src/RCryptoRandom.cxx src/String.cxx src/Stringio.cxx src/TApplication.cxx @@ -288,3 +290,70 @@ generateManual(rootclingMan ${CMAKE_SOURCE_DIR}/core/dictgen/src/rootcling-argpa endif() ROOT_ADD_TEST_SUBDIRECTORY(test) + +if(UNIX) + # Determine cryptographic random number generator + + CHECK_CXX_SOURCE_COMPILES("#include + int main() { char buf[32]; arc4random_buf(buf, 32); return 0;}" found_arc4) + + if(found_arc4) + message(STATUS "Found arc4random_buf in stdlib.h") + target_compile_definitions(Core PRIVATE R__ARC4_STDLIB) + else() + set(OLD_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) + set(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + if(DEFINED LIBBSDROOT) + set(CMAKE_REQUIRED_INCLUDES ${LIBBSDROOT}/include) + set(CMAKE_REQUIRED_LIBRARIES ${LIBBSDROOT}/lib/libbsd.so) + endif() + CHECK_CXX_SOURCE_COMPILES("#include + int main() { char buf[32]; arc4random_buf(buf, 32); return 0;}" found_arc4_bsd) + set(CMAKE_REQUIRED_INCLUDES ${OLD_CMAKE_REQUIRED_INCLUDES}) + set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES}) + if(found_arc4_bsd) + message(STATUS "Found arc4random_buf in bsd/stdlib.h") + target_compile_definitions(Core PRIVATE R__ARC4_BSDLIB) + if(DEFINED LIBBSDROOT) + target_include_directories(Core PRIVATE ${LIBBSDROOT}/include) + target_link_libraries(Core PRIVATE ${LIBBSDROOT}/lib/libbsd.so) + endif() + else() + CHECK_CXX_SOURCE_COMPILES("#include + int main() { char buf[32]; int res = getrandom(buf, 32, GRND_NONBLOCK); return 0;}" found_getrandom) + if(found_getrandom) + message(STATUS "Found getrandom in sys/random.h") + target_compile_definitions(Core PRIVATE R__GETRANDOM_CLIB) + else() + CHECK_CXX_SOURCE_RUNS(" + #include + + int main() { + std::ifstream urandom{\"/dev/urandom\"}; + if (!urandom) { + // This will make the CMake command fail + return 1; + } + + constexpr int len{32}; + char buf[len]; + for (int n = 0; n < len; n++) buf[n] = 0; + urandom.read(buf, len); + + int nmatch = 0; + for (int n = 0; n < len; n++) + if (buf[n] == 0) nmatch++; + + // Fail if no values have changed + return nmatch != len ? 0 : 1; + }" found_urandom) + if(found_urandom) + message(STATUS "Found random device in /dev/urandom") + target_compile_definitions(Core PRIVATE R__USE_URANDOM) + else() + message(FATAL_ERROR "Fail to detect cryptographic random generator") + endif() + endif() + endif() + endif() +endif(UNIX) diff --git a/core/base/inc/ROOT/RCryptoRandom.hxx b/core/base/inc/ROOT/RCryptoRandom.hxx new file mode 100644 index 0000000000000..b028a45951238 --- /dev/null +++ b/core/base/inc/ROOT/RCryptoRandom.hxx @@ -0,0 +1,27 @@ +/// \file ROOT/RCryptoRandom.hxx +/// \ingroup Base +/// \date 2026-04-24 + +/************************************************************************* + * Copyright (C) 1995-2026, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_RCryptoRandom +#define ROOT_RCryptoRandom + +#include + +namespace ROOT { +namespace Internal { + +/// Get random bytes from the operating system's cryptographic random number generator +bool GetCryptoRandom(void *buf, std::size_t len); + +} // namespace Internal +} // namespace ROOT + +#endif diff --git a/core/base/inc/TSystem.h b/core/base/inc/TSystem.h index 54f95ac45e8b9..eba3e77c83d64 100644 --- a/core/base/inc/TSystem.h +++ b/core/base/inc/TSystem.h @@ -369,7 +369,7 @@ class TSystem : public TNamed { void SetErrorStr(const char *errstr); const char *GetErrorStr() const { return GetLastErrorString(); } virtual const char *GetError(); - virtual Int_t GetCryptoRandom(void *buf, Int_t len); + static Int_t GetCryptoRandom(void *buf, Int_t len); void RemoveOnExit(TObject *obj); virtual const char *HostName(); virtual void NotifyApplicationCreated(); diff --git a/core/base/src/RCryptoRandom.cxx b/core/base/src/RCryptoRandom.cxx new file mode 100644 index 0000000000000..8793c9d57ef7f --- /dev/null +++ b/core/base/src/RCryptoRandom.cxx @@ -0,0 +1,44 @@ +#include "ROOT/RConfig.hxx" +#include "ROOT/RCryptoRandom.hxx" + +#ifdef WIN32 +#include +#else +#if defined(R__ARC4_STDLIB) +#include +#elif defined(R__ARC4_BSDLIB) +#include +#elif defined(R__GETRANDOM_CLIB) +#include +#elif defined(R__USE_URANDOM) +#include +#endif +#endif + +bool ROOT::Internal::GetCryptoRandom(void *buf, std::size_t len) +{ +#ifdef WIN32 + + auto rv = BCryptGenRandom((BCRYPT_ALG_HANDLE)NULL, (PUCHAR)buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); + return rv == STATUS_SUCCESS; + +#else // UNIX + +#if defined(R__ARC4_STDLIB) || defined(R__ARC4_BSDLIB) + arc4random_buf(buf, len); + return true; +#elif defined(R__GETRANDOM_CLIB) + return getrandom(buf, len, GRND_NONBLOCK) == len; +#elif defined(R__USE_URANDOM) + std::ifstream urandom{"/dev/urandom"}; + if (!urandom) + return false; + urandom.read(reinterpret_cast(buf), len); + return true; +#else +#error "Reliable cryptographic random function not defined" + return false; +#endif + +#endif +} diff --git a/core/base/src/TSystem.cxx b/core/base/src/TSystem.cxx index 2585dd507270d..f9811bdc34643 100644 --- a/core/base/src/TSystem.cxx +++ b/core/base/src/TSystem.cxx @@ -22,6 +22,7 @@ allows a simple partial implementation for new OS'es. */ #include +#include #include "strlcpy.h" #include "TSystem.h" #include "TApplication.h" @@ -261,10 +262,13 @@ const char *TSystem::GetError() /// Fill provided buffer with random values /// Returns number of bytes written to buffer or -1 in case of error -Int_t TSystem::GetCryptoRandom(void * /* buf */, Int_t /* len */) +Int_t TSystem::GetCryptoRandom(void *buf, Int_t len) { - Error("GetCryptoRandom", "Not implemented"); - return -1; + if (len < 0) { + return false; + } + const auto rv = ROOT::Internal::GetCryptoRandom(buf, len); + return rv ? len : -1; } diff --git a/core/base/test/CMakeLists.txt b/core/base/test/CMakeLists.txt index c88591be44568..71787ae28a42e 100644 --- a/core/base/test/CMakeLists.txt +++ b/core/base/test/CMakeLists.txt @@ -26,6 +26,8 @@ ROOT_ADD_GTEST(CoreErrorTests TErrorTests.cxx LIBRARIES Core) ROOT_ADD_GTEST(CoreSystemTests TSystemTests.cxx LIBRARIES Core) +ROOT_ADD_GTEST(CoreCryptoRandomTest CryptoRandomTest.cxx LIBRARIES Core) + ROOT_ADD_GTEST(CoreColorTests TColorTests.cxx LIBRARIES Core) if(CMAKE_SYSTEM_NAME MATCHES "Darwin" AND CMAKE_HOST_SYSTEM_VERSION VERSION_GREATER_EQUAL 25.4) set_tests_properties(gtest-core-base-CoreColorTests PROPERTIES DISABLED True) diff --git a/core/base/test/CryptoRandomTest.cxx b/core/base/test/CryptoRandomTest.cxx new file mode 100644 index 0000000000000..a811b6b9ab336 --- /dev/null +++ b/core/base/test/CryptoRandomTest.cxx @@ -0,0 +1,39 @@ +#include "gtest/gtest.h" + +#include + +TEST(TSystem, CryptoRandom) +{ + // test with 512 bits, longer keys may not work + + const int len = 64; + uint8_t buf[64]; + + for (int n = 0; n < len; n++) + buf[n] = 0; + + EXPECT_TRUE(ROOT::Internal::GetCryptoRandom(buf, len)); + + int nmatch = 0; + + for (int n = 0; n < len; n++) + if (buf[n] == 0) + nmatch++; + + // check that values in buffer changed + EXPECT_TRUE(nmatch != len); + + for (int n = 0; n < len; n++) + buf[n] = n; + + EXPECT_TRUE(ROOT::Internal::GetCryptoRandom(buf, len)); + + nmatch = 0; + + for (int n = 0; n < len; n++) + if (buf[n] == n) + nmatch++; + + // check that values in buffer changed + EXPECT_TRUE(nmatch != len); +} diff --git a/core/base/test/TSystemTests.cxx b/core/base/test/TSystemTests.cxx index 03d87fab297f3..b33ddbf253fde 100644 --- a/core/base/test/TSystemTests.cxx +++ b/core/base/test/TSystemTests.cxx @@ -56,43 +56,3 @@ TEST(TSystem, TempFileSuffix) gSystem->Unlink(fname); } - -TEST(TSystem, CryptoRandom) -{ - // test with 512 bits, longer keys may not work - - const int len = 64; - uint8_t buf[64]; - - for (int n = 0; n < len; n++) - buf[n] = 0; - - auto res = gSystem->GetCryptoRandom(buf, len); - - EXPECT_EQ(res, len); - - int nmatch = 0; - - for (int n = 0; n < len; n++) - if (buf[n] == 0) - nmatch++; - - // check that values in buffer changed - EXPECT_TRUE(nmatch != len); - - for (int n = 0; n < len; n++) - buf[n] = n; - - res = gSystem->GetCryptoRandom(buf, len); - - EXPECT_EQ(res, len); - - nmatch = 0; - - for (int n = 0; n < len; n++) - if (buf[n] == n) - nmatch++; - - // check that values in buffer changed - EXPECT_TRUE(nmatch != len); -} diff --git a/core/unix/CMakeLists.txt b/core/unix/CMakeLists.txt index 9f76985a8c54a..f1bfed48174af 100644 --- a/core/unix/CMakeLists.txt +++ b/core/unix/CMakeLists.txt @@ -20,68 +20,4 @@ if (CMAKE_SYSTEM_NAME MATCHES FreeBSD) target_link_libraries(Core PRIVATE execinfo util) endif() -CHECK_CXX_SOURCE_COMPILES("#include -int main() { char buf[32]; arc4random_buf(buf, 32); return 0;}" found_arc4) - -if(found_arc4) - message(STATUS "Found arc4random_buf in stdlib.h") - target_compile_definitions(Core PRIVATE R__ARC4_STDLIB) -else() - set(OLD_CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES}) - set(OLD_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) - if(DEFINED LIBBSDROOT) - set(CMAKE_REQUIRED_INCLUDES ${LIBBSDROOT}/include) - set(CMAKE_REQUIRED_LIBRARIES ${LIBBSDROOT}/lib/libbsd.so) - endif() - CHECK_CXX_SOURCE_COMPILES("#include - int main() { char buf[32]; arc4random_buf(buf, 32); return 0;}" found_arc4_bsd) - set(CMAKE_REQUIRED_INCLUDES ${OLD_CMAKE_REQUIRED_INCLUDES}) - set(CMAKE_REQUIRED_LIBRARIES ${OLD_CMAKE_REQUIRED_LIBRARIES}) - if(found_arc4_bsd) - message(STATUS "Found arc4random_buf in bsd/stdlib.h") - target_compile_definitions(Core PRIVATE R__ARC4_BSDLIB) - if(DEFINED LIBBSDROOT) - target_include_directories(Core PRIVATE ${LIBBSDROOT}/include) - target_link_libraries(Core PRIVATE ${LIBBSDROOT}/lib/libbsd.so) - endif() - else() - CHECK_CXX_SOURCE_COMPILES("#include - int main() { char buf[32]; int res = getrandom(buf, 32, GRND_NONBLOCK); return 0;}" found_getrandom) - if(found_getrandom) - message(STATUS "Found getrandom in sys/random.h") - target_compile_definitions(Core PRIVATE R__GETRANDOM_CLIB) - else() - CHECK_CXX_SOURCE_RUNS(" - #include - - int main() { - std::ifstream urandom{\"/dev/urandom\"}; - if (!urandom) { - // This will make the CMake command fail - return 1; - } - - constexpr int len{32}; - char buf[len]; - for (int n = 0; n < len; n++) buf[n] = 0; - urandom.read(buf, len); - - int nmatch = 0; - for (int n = 0; n < len; n++) - if (buf[n] == 0) nmatch++; - - // Fail if no values have changed - return nmatch != len ? 0 : 1; - }" found_urandom) - if(found_urandom) - message(STATUS "Found random device in /dev/urandom") - target_compile_definitions(Core PRIVATE R__USE_URANDOM) - else() - message(FATAL_ERROR "Fail to detect cryptographic random generator") - endif() - endif() - endif() -endif() - - ROOT_INSTALL_HEADERS() diff --git a/core/unix/inc/TUnixSystem.h b/core/unix/inc/TUnixSystem.h index 9f89288d96de1..8d92bd4597a85 100644 --- a/core/unix/inc/TUnixSystem.h +++ b/core/unix/inc/TUnixSystem.h @@ -78,7 +78,6 @@ class TUnixSystem : public TSystem { void SetProgname(const char *name) override; void SetDisplay() override; const char *GetError() override; - Int_t GetCryptoRandom(void *buf, Int_t len) override; const char *HostName() override; //---- EventLoop -------------------------------------------- diff --git a/core/unix/src/TUnixSystem.cxx b/core/unix/src/TUnixSystem.cxx index 6ae409145d3d3..17efe4c182da5 100644 --- a/core/unix/src/TUnixSystem.cxx +++ b/core/unix/src/TUnixSystem.cxx @@ -731,30 +731,6 @@ const char *TUnixSystem::GetError() #endif } -//////////////////////////////////////////////////////////////////////////////// -/// Return cryptographic random number -/// Fill provided buffer with random values -/// Returns number of bytes written to buffer or -1 in case of error - -Int_t TUnixSystem::GetCryptoRandom(void *buf, Int_t len) -{ -#if defined(R__ARC4_STDLIB) || defined(R__ARC4_BSDLIB) - arc4random_buf(buf, len); - return len; -#elif defined(R__GETRANDOM_CLIB) - return getrandom(buf, len, GRND_NONBLOCK); -#elif defined(R__USE_URANDOM) - std::ifstream urandom{"/dev/urandom"}; - if (!urandom) - return -1; - urandom.read(reinterpret_cast(buf), len); - return len; -#else -#error "Reliable cryptographic random function not defined" - return -1; -#endif -} - //////////////////////////////////////////////////////////////////////////////// /// Return the system's host name. @@ -4298,7 +4274,7 @@ int TUnixSystem::UnixUnixConnect(const char *sockpath) /// Use tcpwindowsize to specify the size of the receive buffer, it has /// to be specified here to make sure the window scale option is set (for /// tcpwindowsize > 65KB and for platforms supporting window scaling). -/// The socketBindOption parameter allows to specify how the socket will be +/// The socketBindOption parameter allows to specify how the socket will be /// bound. See the documentation of ESocketBindOption for the details. /// Returns socket fd or -1 if socket() failed, -2 if bind() failed /// or -3 if listen() failed. @@ -4378,7 +4354,7 @@ int TUnixSystem::UnixTcpService(int port, Bool_t reuse, int backlog, /// how many sockets can be waiting to be accepted. If port is 0 a port /// scan will be done to find a free port. This option is mutual exlusive /// with the reuse option. -/// The socketBindOption parameter allows to specify how the socket will be +/// The socketBindOption parameter allows to specify how the socket will be /// bound. See the documentation of ESocketBindOption for the details. int TUnixSystem::UnixUdpService(int port, int backlog, ESocketBindOption socketBindOption) @@ -5268,10 +5244,10 @@ static void GetLinuxMemInfo(MemInfo_t *meminfo) /* * Compute memory partition like procps(free), see https://gitlab.com/procps-ng/procps/-/blob/master/proc/sysinfo.c - * + * * fMemShared is a part of Cached (see https://lore.kernel.org/patchwork/patch/648763/), does not subtract twice from used */ - + meminfo->fMemCached = meminfo->fMemCached + meminfo->fSReclaimable - meminfo->fMemShared; const Int_t usedDiff = meminfo->fMemFree + meminfo->fMemCached + meminfo->fSReclaimable + meminfo->fMemBuffer; diff --git a/core/winnt/inc/TWinNTSystem.h b/core/winnt/inc/TWinNTSystem.h index c4fe560ebff12..91092a4541604 100644 --- a/core/winnt/inc/TWinNTSystem.h +++ b/core/winnt/inc/TWinNTSystem.h @@ -101,7 +101,6 @@ class TWinNTSystem : public TSystem { const char *BaseName(const char *name) override; void SetProgname(const char *name) override; const char *GetError() override; - Int_t GetCryptoRandom(void *buf, Int_t len) override; const char *HostName() override; void *GetGUIThreadHandle() const {return fGUIThreadHandle;} ULong_t GetGUIThreadId() const {return fGUIThreadId;} diff --git a/core/winnt/src/TWinNTSystem.cxx b/core/winnt/src/TWinNTSystem.cxx index 42d8329ba1970..98d10a5319893 100644 --- a/core/winnt/src/TWinNTSystem.cxx +++ b/core/winnt/src/TWinNTSystem.cxx @@ -1266,17 +1266,6 @@ const char *TWinNTSystem::GetError() return sys_errlist[err]; } -//////////////////////////////////////////////////////////////////////////////// -/// Return cryptographic random number -/// Fill provided buffer with random values -/// Returns number of bytes written to buffer or -1 in case of error - -Int_t TWinNTSystem::GetCryptoRandom(void *buf, Int_t len) -{ - auto res = BCryptGenRandom((BCRYPT_ALG_HANDLE) NULL, (PUCHAR) buf, (ULONG) len, BCRYPT_USE_SYSTEM_PREFERRED_RNG); - return !res ? len : -1; -} - //////////////////////////////////////////////////////////////////////////////// /// Return the system's host name. @@ -5384,7 +5373,7 @@ int TWinNTSystem::OpenConnection(const char *server, int port, int tcpwindowsize /// Use tcpwindowsize to specify the size of the receive buffer, it has /// to be specified here to make sure the window scale option is set (for /// tcpwindowsize > 65KB and for platforms supporting window scaling). -/// The socketBindOption parameter allows to specify how the socket will be +/// The socketBindOption parameter allows to specify how the socket will be /// bound. See the documentation of ESocketBindOption for the details. /// Returns socket fd or -1 if socket() failed, -2 if bind() failed /// or -3 if listen() failed. @@ -5474,7 +5463,7 @@ int TWinNTSystem::AnnounceUdpService(int port, int backlog, ESocketBindOption so // how many sockets can be waiting to be accepted. If port is 0 a port // scan will be done to find a free port. This option is mutual exlusive // with the reuse option. - // The socketBindOption parameter allows to specify how the socket will be + // The socketBindOption parameter allows to specify how the socket will be // bound. See the documentation of ESocketBindOption for the details. const short kSOCKET_MINPORT = 5000, kSOCKET_MAXPORT = 15000; From 3417ff4de93f991b323b02cf843204e5ccc62ce2 Mon Sep 17 00:00:00 2001 From: Jakob Blomer Date: Fri, 24 Apr 2026 10:26:57 +0200 Subject: [PATCH 6/6] [io] use UUIDv4 in TFile unconditionally --- core/base/inc/TDirectory.h | 2 +- core/base/src/TDirectory.cxx | 8 -------- core/base/src/TUUID.cxx | 7 ++++--- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/core/base/inc/TDirectory.h b/core/base/inc/TDirectory.h index a95e91d236111..744848ae72948 100644 --- a/core/base/inc/TDirectory.h +++ b/core/base/inc/TDirectory.h @@ -140,7 +140,7 @@ can be replaced with the simpler and exception safe: TObject *fMother{nullptr}; ///< pointer to mother of the directory TList *fList{nullptr}; ///< List of objects in memory - TUUID fUUID; ///< Unique identifier + TUUID fUUID{TUUID::UUIDv4()}; ///< Unique identifier mutable TString fPathBuffer; /// + #include "TROOT.h" #include "TDatime.h" #include "TUUID.h" @@ -156,9 +158,8 @@ TUUID TUUID::UUIDv4() // Ensure we can treat the memory starting at uuid.fTimeLow as an array of 16 octets assert(&uuid.fNode[5] - reinterpret_cast(&uuid.fTimeLow) + 1 == 16); - R__ASSERT(gSystem); - const auto rv = gSystem->GetCryptoRandom(&uuid.fTimeLow, 16); - R__ASSERT(rv == 16); + const auto rv = ROOT::Internal::GetCryptoRandom(&uuid.fTimeLow, 16); + R__ASSERT(rv); // Fix up variant uuid.fClockSeqHiAndReserved = (uuid.fClockSeqHiAndReserved & 0x3F) | (2 << 6); // Fix up version