From 7beec45957df128b9fed8bd9ed08da15ba4f9a4a 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 39cfe9d91b494e63cf794206d82a2cd254022c37 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 | 5 +++++ core/base/src/TUUID.cxx | 31 +++++++++++++++++++++++++++++++ core/base/test/CMakeLists.txt | 2 ++ core/base/test/UUIDTest.cxx | 22 ++++++++++++++++++++++ 4 files changed, 60 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..bd44e97c16050 100644 --- a/core/base/inc/TUUID.h +++ b/core/base/inc/TUUID.h @@ -63,11 +63,16 @@ class TUUID { void GetRandomInfo(UChar_t seed[16]); void SetFromString(const char *uuid_str); + struct TV4Marker {}; + explicit TUUID(TV4Marker); + public: TUUID(); TUUID(const char *uuid_str); virtual ~TUUID(); + 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..4b3d0507d94c9 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,36 @@ system clock catches up. #endif #include +//////////////////////////////////////////////////////////////////////////////// +/// 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. + +TUUID TUUID::UUIDv4() +{ + return TUUID{TV4Marker()}; +} + +//////////////////////////////////////////////////////////////////////////////// +/// Create a version 4 UUID. + +TUUID::TUUID(TV4Marker) +{ + // Ensure we can treat the memory starting at uuid.fTimeLow as an array of 16 octets + assert(&fNode[5] - reinterpret_cast(&fTimeLow) + 1 == 16); + + R__ASSERT(gSystem); + const auto rv = gSystem->GetCryptoRandom(&fTimeLow, 16); + R__ASSERT(rv == 16); + // Fix up variant + fClockSeqHiAndReserved = (fClockSeqHiAndReserved & 0x3F) | (2 << 6); + // Fix up version + fTimeHiAndVersion = (fTimeHiAndVersion & 0x0FFF) | (4 << 12); + + // TODO(jblomer): we do what the default constructor does but is this still used? Can it be deprecated? + fUUIDIndex = 1 << 30; +} //////////////////////////////////////////////////////////////////////////////// /// 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 276263559ed0480fc0ed84b963e176d376da114a 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 4b3d0507d94c9..ca583d35214ec 100644 --- a/core/base/src/TUUID.cxx +++ b/core/base/src/TUUID.cxx @@ -600,7 +600,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 943987af47e208b296f0c850cce637846730fbf0 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 de69a0ff078c810ba50927ef0fdba4b82360ec3e 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 | 26 +++++++++++ core/base/inc/TSystem.h | 2 +- core/base/src/RCryptoRandom.cxx | 47 +++++++++++++++++++ core/base/src/TSystem.cxx | 12 +++-- 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, 198 insertions(+), 152 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..a67b485c6d8d0 --- /dev/null +++ b/core/base/inc/ROOT/RCryptoRandom.hxx @@ -0,0 +1,26 @@ +/// \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 + +namespace ROOT { +namespace Internal { + +/// Get random bytes from the operating system's cryptographic random number generator +/// The requested number of bytes must not exceed 256. +bool GetCryptoRandom(void *buf, unsigned int 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..304a806c6ce18 --- /dev/null +++ b/core/base/src/RCryptoRandom.cxx @@ -0,0 +1,47 @@ +#include "ROOT/RConfig.hxx" +#include "ROOT/RCryptoRandom.hxx" + +#ifdef WIN32 +#include "Windows4Root.h" +#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, unsigned int len) +{ + if (len > 256) + return false; + +#ifdef WIN32 + + return BCryptGenRandom((BCRYPT_ALG_HANDLE)NULL, (PUCHAR)buf, (ULONG)len, BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0; + +#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 urandom.good(); +#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..9eef2c91eaec3 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" @@ -258,13 +259,16 @@ const char *TSystem::GetError() //////////////////////////////////////////////////////////////////////////////// /// Return cryptographic random number -/// Fill provided buffer with random values +/// Fill provided buffer with random values. The number of requested random bytes must not exceed 256. /// 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 -1; + } + 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 ec0de0a05da44d04d48884178943f5ccfa91d0f6 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" @@ -165,9 +167,8 @@ TUUID::TUUID(TV4Marker) // Ensure we can treat the memory starting at uuid.fTimeLow as an array of 16 octets assert(&fNode[5] - reinterpret_cast(&fTimeLow) + 1 == 16); - R__ASSERT(gSystem); - const auto rv = gSystem->GetCryptoRandom(&fTimeLow, 16); - R__ASSERT(rv == 16); + const auto rv = ROOT::Internal::GetCryptoRandom(&fTimeLow, 16); + R__ASSERT(rv); // Fix up variant fClockSeqHiAndReserved = (fClockSeqHiAndReserved & 0x3F) | (2 << 6); // Fix up version