From 8bca7f398aafd10f43331b0a874cf88a4a2e1de1 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Tue, 4 Mar 2025 18:49:21 +0100 Subject: [PATCH 1/2] [io] properly stream TClonesArray with empty slots Fixes https://its.cern.ch/jira/browse/ROOT-6788 --- io/io/src/TStreamerInfoActions.cxx | 3 ++- io/io/test/TBufferFileTests.cxx | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 35f315029fce5..28ff099d5510f 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -2497,7 +2497,8 @@ namespace TStreamerInfoActions static INLINE_TEMPLATE_ARGS Int_t LoopOverCollection(TBuffer &buf, void *start, const void *end, const TConfiguration *config) { for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) { - action(buf, *(void**)iter, config); + if (*(void**)iter) + action(buf, *(void**)iter, config); } return 0; } diff --git a/io/io/test/TBufferFileTests.cxx b/io/io/test/TBufferFileTests.cxx index 30a5704d412fe..3d374c9ea0524 100644 --- a/io/io/test/TBufferFileTests.cxx +++ b/io/io/test/TBufferFileTests.cxx @@ -2,8 +2,12 @@ #include "TBufferFile.h" #include "TClass.h" +#include "TClonesArray.h" +#include "TObjString.h" #include #include +#include + // Tests ROOT-8367 TEST(TBufferFile, ROOT_8367) @@ -26,3 +30,20 @@ TEST(TBufferFile, ROOT_8367) EXPECT_FLOAT_EQ(v2[6], 7.); EXPECT_EQ(v2.size(), 7); } + +// https://its.cern.ch/jira/browse/ROOT-6788 +TEST(TBufferFile, ROOT_6788) +{ + TClonesArray clArray(TObjString::Class(), 100); + for (Int_t i=0; i<28; i++) { + new (clArray[i]) TObjString(); + } + TBufferFile buf(TBuffer::kWrite, 10000); + for (Int_t i=0; i<27; i++) { + delete clArray.RemoveAt(i); + } + buf.SetBufferOffset(0); + buf.MapObject(&clArray); + clArray.Streamer(buf); +} + From 090ca9eb1adc2081300fe61cd0239e683ad0fb50 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Sun, 29 Mar 2026 11:44:32 +0200 Subject: [PATCH 2/2] attempt to apply pcanal's suggestion Apply suggestion from @pcanal Co-authored-by: Philippe Canal apply pcanals hints --- io/io/src/TStreamerInfoActions.cxx | 87 +++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/io/io/src/TStreamerInfoActions.cxx b/io/io/src/TStreamerInfoActions.cxx index 28ff099d5510f..e0348bcc5fa14 100644 --- a/io/io/src/TStreamerInfoActions.cxx +++ b/io/io/src/TStreamerInfoActions.cxx @@ -2499,6 +2499,8 @@ namespace TStreamerInfoActions for(void *iter = start; iter != end; iter = (char*)iter + sizeof(void*) ) { if (*(void**)iter) action(buf, *(void**)iter, config); + else + buf << static_cast(nullptr); } return 0; } @@ -2518,8 +2520,10 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { - T *x = (T*)( ((char*) (*(void**)iter) ) + offset ); - buf >> *x; + if (*(void**)iter) { + T *x = (T*)( ((char*) (*(void**)iter) ) + offset ); + buf >> *x; + } } return 0; } @@ -2533,8 +2537,10 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { buf >> temp; - To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); - *x = (To)temp; + if (*(void**)iter) { + To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); + *x = (To)temp; + } } return 0; } @@ -2550,12 +2556,15 @@ namespace TStreamerInfoActions for(; iter != end; iter = (char*)iter + sizeof(void*) ) { buf >> temp; - if ((temp & kIsReferenced) != 0) { - HandleReferencedTObject(buf,*(void**)iter,config); - } + if (*(void**)iter) + { + if ((temp & kIsReferenced) != 0) { + HandleReferencedTObject(buf,*(void**)iter,config); + } - To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); - *x = (To)temp; + To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); + *x = (To)temp; + } } return 0; } @@ -2571,8 +2580,10 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { buf.ReadWithFactor(&temp, conf->fFactor, conf->fXmin); - To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); - *x = (To)temp; + if (*(void**)iter) { + To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); + *x = (To)temp; + } } return 0; } @@ -2588,8 +2599,10 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { buf.ReadWithNbits(&temp, conf->fNbits); - To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); - *x = (To)temp; + if (*(void**)iter) { + To *x = (To*)( ((char*) (*(void**)iter) ) + offset ); + *x = (To)temp; + } } return 0; } @@ -2601,8 +2614,12 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { - T *x = (T*)( ((char*) (*(void**)iter) ) + offset ); - buf << *x; + if (*(void**)iter) { + T *x = (T*)( ((char*) (*(void**)iter) ) + offset ); + buf << *x; + } + else + buf << static_cast(nullptr); } return 0; } @@ -2614,9 +2631,13 @@ namespace TStreamerInfoActions const Int_t offset = config->fOffset; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { - From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); - To to = (To)(*from); - buf << to; + if (*(void**)iter) { + From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); + To to = (To)(*from); + buf << to; + } else { + buf << static_cast(nullptr); + } } return 0; } @@ -2631,8 +2652,13 @@ namespace TStreamerInfoActions for(; iter != end; iter = (char*)iter + sizeof(void*) ) { From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); - To to = (To)(*from); - WriteCompressed(buf, &to, elem); + if (*(void**)iter) { + To to = (To)(*from); + WriteCompressed(buf, &to, elem); + } else { + To to; // uninitialized value + WriteCompressed(buf, &to, elem); + } } return 0; } @@ -2645,9 +2671,14 @@ namespace TStreamerInfoActions const TStreamerElement *elem = config->fCompInfo->fElem; for(; iter != end; iter = (char*)iter + sizeof(void*) ) { - From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); - To to = (To)(*from); - WriteCompressed(buf, &to, elem); + if(*(void**)iter) { + From *from = (From*)( ((char*) (*(void**)iter) ) + offset ); + To to = (To)(*from); + WriteCompressed(buf, &to, elem); + } else { + To to; // uninitialized value + WriteCompressed(buf, &to, elem); + } } return 0; } @@ -2694,14 +2725,20 @@ namespace TStreamerInfoActions { Int_t n = ( ((void**)end) - ((void**)iter) ); char **arr = (char**)iter; - return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 ); + if (arr) + return ((TStreamerInfo*)config->fInfo)->ReadBuffer(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, /*narr*/ n, config->fOffset, 1|2 ); + else + return 0; } static INLINE_TEMPLATE_ARGS Int_t GenericWrite(TBuffer &buf, void *iter, const void *end, const TConfiguration *config) { Int_t n = ( ((void**)end) - ((void**)iter) ); char **arr = (char**)iter; - return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 ); + if (arr) + return ((TStreamerInfo*)config->fInfo)->WriteBufferAux(buf, arr, &(config->fCompInfo), /*first*/ 0, /*last*/ 1, n, config->fOffset, 1|2 ); + else + return 0; } };