From 301ad29bfebc3bd5f19637e341ee11280f111b38 Mon Sep 17 00:00:00 2001 From: ferdymercury Date: Mon, 11 Aug 2025 14:41:45 +0200 Subject: [PATCH 01/22] [io] Properly abort when buffer size overflows max integer Fixes https://github.com/root-project/root/issues/14770 [io] add more checks in TBuffer functions as suggested by jblomer --- core/base/inc/TBuffer.h | 38 ++++++------ core/base/inc/TDirectory.h | 18 +++--- core/base/inc/TObject.h | 4 +- core/base/src/TBuffer.cxx | 30 +++++----- core/base/src/TDirectory.cxx | 9 +-- core/base/src/TObject.cxx | 4 +- core/cont/inc/TCollection.h | 4 +- core/cont/inc/TMap.h | 4 +- core/cont/src/TCollection.cxx | 4 +- core/cont/src/TMap.cxx | 4 +- hist/hbook/inc/THbookBranch.h | 4 +- hist/hbook/src/THbookBranch.cxx | 4 +- hist/hbook/src/THbookFile.cxx | 2 +- hist/hist/inc/TH1.h | 4 +- hist/hist/inc/TProfile.h | 2 +- hist/hist/inc/TProfile2D.h | 2 +- hist/hist/inc/TProfile3D.h | 2 +- hist/hist/src/TH1.cxx | 7 ++- hist/hist/src/TProfile.cxx | 4 +- hist/hist/src/TProfile2D.cxx | 4 +- hist/hist/src/TProfile3D.cxx | 4 +- hist/hist/src/TScatter.cxx | 3 + hist/histpainter/src/TPainter3dAlgorithms.cxx | 4 +- io/io/inc/ROOT/TBufferMerger.hxx | 2 +- io/io/inc/TBufferFile.h | 22 +++---- io/io/inc/TBufferIO.h | 16 ++--- io/io/inc/TBufferText.h | 12 ++-- io/io/inc/TDirectoryFile.h | 12 ++-- io/io/inc/TFile.h | 18 +++--- io/io/inc/TFileCacheRead.h | 4 +- io/io/inc/TFileCacheWrite.h | 2 +- io/io/inc/TKey.h | 12 ++-- io/io/inc/TMapFile.h | 2 +- io/io/src/TBufferFile.cxx | 40 ++++++------- io/io/src/TBufferIO.cxx | 16 +++-- io/io/src/TBufferMergerFile.cxx | 2 +- io/io/src/TDirectoryFile.cxx | 27 ++++++--- io/io/src/TFile.cxx | 52 ++++++++++++----- io/io/src/TFileCacheRead.cxx | 7 ++- io/io/src/TFileCacheWrite.cxx | 9 ++- io/io/src/TKey.cxx | 33 ++++++++--- io/io/src/TMapFile.cxx | 2 +- io/sql/inc/TSQLFile.h | 8 +-- io/sql/src/TSQLFile.cxx | 4 +- io/xml/inc/TXMLFile.h | 8 +-- io/xml/src/TXMLFile.cxx | 4 +- main/src/h2root.cxx | 4 +- net/net/inc/TMessage.h | 4 +- net/net/inc/TParallelMergingFile.h | 4 +- net/net/src/TMessage.cxx | 4 +- net/net/src/TParallelMergingFile.cxx | 4 +- roottest/root/meta/MemberComments.ref | 4 +- roottest/root/meta/MemberComments_win32.ref | 4 +- roottest/root/meta/MemberComments_win64.ref | 4 +- tree/dataframe/src/RDFSnapshotHelpers.cxx | 2 +- tree/ntuple/src/RFieldMeta.cxx | 2 +- tree/tree/inc/TBranch.h | 6 +- tree/tree/inc/TBranchClones.h | 8 +-- tree/tree/inc/TBranchElement.h | 24 ++++---- tree/tree/inc/TBranchObject.h | 8 +-- tree/tree/inc/TBranchSTL.h | 4 +- tree/tree/inc/TBufferSQL.h | 4 +- tree/tree/inc/TChain.h | 2 +- tree/tree/inc/TNtuple.h | 2 +- tree/tree/inc/TNtupleD.h | 2 +- tree/tree/inc/TTree.h | 58 +++++++++---------- tree/tree/inc/TTreeCache.h | 4 +- tree/tree/inc/TTreeCacheUnzip.h | 2 +- tree/tree/inc/TTreeSQL.h | 18 +++--- tree/tree/src/TBranch.cxx | 12 +++- tree/tree/src/TBranchClones.cxx | 10 ++-- tree/tree/src/TBranchElement.cxx | 30 +++++----- tree/tree/src/TBranchObject.cxx | 10 ++-- tree/tree/src/TBranchSTL.cxx | 8 ++- tree/tree/src/TBufferSQL.cxx | 4 +- tree/tree/src/TChain.cxx | 2 +- tree/tree/src/TNtuple.cxx | 2 +- tree/tree/src/TNtupleD.cxx | 2 +- tree/tree/src/TTree.cxx | 36 ++++++------ tree/tree/src/TTreeCache.cxx | 8 +-- tree/tree/src/TTreeCacheUnzip.cxx | 6 +- tree/tree/src/TTreeSQL.cxx | 18 +++--- 82 files changed, 452 insertions(+), 353 deletions(-) diff --git a/core/base/inc/TBuffer.h b/core/base/inc/TBuffer.h index e383bb738d672..edafce36448f7 100644 --- a/core/base/inc/TBuffer.h +++ b/core/base/inc/TBuffer.h @@ -64,9 +64,9 @@ class TBuffer : public TObject { void operator=(const TBuffer &) = delete; Int_t Read(const char *name) override { return TObject::Read(name); } - Int_t Write(const char *name, Int_t opt, Int_t bufsize) override + Int_t Write(const char *name, Int_t opt, Long64_t bufsize) override { return TObject::Write(name, opt, bufsize); } - Int_t Write(const char *name, Int_t opt, Int_t bufsize) const override + Int_t Write(const char *name, Int_t opt, Long64_t bufsize) const override { return TObject::Write(name, opt, bufsize); } public: @@ -78,8 +78,8 @@ class TBuffer : public TObject { enum { kInitialSize = 1024, kMinimalSize = 128 }; TBuffer(EMode mode); - TBuffer(EMode mode, Int_t bufsize); - TBuffer(EMode mode, Int_t bufsize, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); + TBuffer(EMode mode, Long64_t bufsize); + TBuffer(EMode mode, Long64_t bufsize, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); virtual ~TBuffer(); Int_t GetBufferVersion() const { return fVersion; } @@ -87,10 +87,10 @@ class TBuffer : public TObject { Bool_t IsWriting() const { return (fMode & kWrite) != 0; } void SetReadMode(); void SetWriteMode(); - void SetBuffer(void *buf, UInt_t bufsize = 0, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); + void SetBuffer(void *buf, Long64_t bufsize = 0, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); ReAllocCharFun_t GetReAllocFunc() const; void SetReAllocFunc(ReAllocCharFun_t reallocfunc = nullptr); - void SetBufferOffset(Int_t offset = 0) { fBufCur = fBuffer+offset; } + void SetBufferOffset(Long64_t offset = 0) { fBufCur = fBuffer+offset; } void SetParent(TObject *parent); TObject *GetParent() const; char *Buffer() const { return fBuffer; } @@ -98,33 +98,33 @@ class TBuffer : public TObject { Int_t BufferSize() const { return fBufSize; } void DetachBuffer() { fBuffer = nullptr; } Int_t Length() const { return (Int_t)(fBufCur - fBuffer); } - void Expand(Int_t newsize, Bool_t copy = kTRUE); // expand buffer to newsize - void AutoExpand(Int_t size_needed); // expand buffer to newsize + void Expand(Long64_t newsize, Bool_t copy = kTRUE); // expand buffer to newsize + void AutoExpand(Long64_t size_needed); // expand buffer to newsize Bool_t ByteSwapBuffer(Long64_t n, EDataType type); // Byte-swap N primitive-elements in the buffer virtual Bool_t CheckObject(const TObject *obj) = 0; virtual Bool_t CheckObject(const void *obj, const TClass *ptrClass) = 0; - virtual Int_t ReadBuf(void *buf, Int_t max) = 0; - virtual void WriteBuf(const void *buf, Int_t max) = 0; + virtual Long64_t ReadBuf(void *buf, Long64_t max) = 0; + virtual void WriteBuf(const void *buf, Long64_t max) = 0; - virtual char *ReadString(char *s, Int_t max) = 0; + virtual char *ReadString(char *s, Long64_t max) = 0; virtual void WriteString(const char *s) = 0; virtual Int_t GetVersionOwner() const = 0; virtual Int_t GetMapCount() const = 0; virtual void GetMappedObject(UInt_t tag, void* &ptr, TClass* &ClassPtr) const = 0; - virtual void MapObject(const TObject *obj, UInt_t offset = 1) = 0; - virtual void MapObject(const void *obj, const TClass *cl, UInt_t offset = 1) = 0; + virtual void MapObject(const TObject *obj, ULong64_t offset = 1) = 0; + virtual void MapObject(const void *obj, const TClass *cl, ULong64_t offset = 1) = 0; virtual void Reset() = 0; virtual void InitMap() = 0; virtual void ResetMap() = 0; virtual void SetReadParam(Int_t mapsize) = 0; virtual void SetWriteParam(Int_t mapsize) = 0; - virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss) = 0; - virtual Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const char *classname) = 0; - virtual void SetByteCount(UInt_t cntpos, Bool_t packInVersion = kFALSE)= 0; + virtual Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss) = 0; + virtual Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const char *classname) = 0; + virtual void SetByteCount(ULong64_t cntpos, Bool_t packInVersion = kFALSE)= 0; virtual void SkipVersion(const TClass *cl = nullptr) = 0; virtual Version_t ReadVersion(UInt_t *start = nullptr, UInt_t *bcnt = nullptr, const TClass *cl = nullptr) = 0; @@ -164,7 +164,7 @@ class TBuffer : public TObject { virtual void SetPidOffset(UShort_t offset) = 0; virtual Int_t GetBufferDisplacement() const = 0; virtual void SetBufferDisplacement() = 0; - virtual void SetBufferDisplacement(Int_t skipped) = 0; + virtual void SetBufferDisplacement(Long64_t skipped) = 0; // basic types and arrays of basic types virtual void ReadFloat16 (Float_t *f, TStreamerElement *ele = nullptr) = 0; @@ -320,8 +320,8 @@ class TBuffer : public TObject { // Utilities for TStreamerInfo virtual void ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t force) = 0; virtual void ForceWriteInfoClones(TClonesArray *a) = 0; - virtual Int_t ReadClones (TClonesArray *a, Int_t nobjects, Version_t objvers) = 0; - virtual Int_t WriteClones(TClonesArray *a, Int_t nobjects) = 0; + virtual Int_t ReadClones (TClonesArray *a, Long64_t nobjects, Version_t objvers) = 0; + virtual Int_t WriteClones(TClonesArray *a, Long64_t nobjects) = 0; // Utilities for TClass virtual Int_t ReadClassEmulated(const TClass *cl, void *object, const TClass *onfile_class = nullptr) = 0; diff --git a/core/base/inc/TDirectory.h b/core/base/inc/TDirectory.h index 9a7e5af175a5c..566eac06e3982 100644 --- a/core/base/inc/TDirectory.h +++ b/core/base/inc/TDirectory.h @@ -254,7 +254,7 @@ can be replaced with the simpler and exception safe: virtual void Save() {} virtual Int_t SaveObjectAs(const TObject * /*obj*/, const char * /*filename*/="", Option_t * /*option*/="") const; virtual void SaveSelf(Bool_t /*force*/ = kFALSE) {} - virtual void SetBufferSize(Int_t /* bufsize */) {} + virtual void SetBufferSize(Long64_t /* bufsize */) {} virtual void SetModified() {} virtual void SetMother(TObject *mother) {fMother = (TObject*)mother;} void SetName(const char* newname) override; @@ -262,12 +262,12 @@ can be replaced with the simpler and exception safe: virtual void SetSeekDir(Long64_t) {} virtual void SetWritable(Bool_t) {} Int_t Sizeof() const override {return 0;} - virtual Int_t Write(const char * /*name*/=nullptr, Int_t /*opt*/=0, Int_t /*bufsize*/=0) override {return 0;} - virtual Int_t Write(const char * /*name*/=nullptr, Int_t /*opt*/=0, Int_t /*bufsize*/=0) const override {return 0;} - virtual Int_t WriteTObject(const TObject *obj, const char *name =nullptr, Option_t * /*option*/="", Int_t /*bufsize*/ =0); + virtual Int_t Write(const char * /*name*/=nullptr, Int_t /*opt*/=0, Long64_t /*bufsize*/=0) override {return 0;} + virtual Int_t Write(const char * /*name*/=nullptr, Int_t /*opt*/=0, Long64_t /*bufsize*/=0) const override {return 0;} + virtual Int_t WriteTObject(const TObject *obj, const char *name =nullptr, Option_t * /*option*/="", Long64_t /*bufsize*/ =0); private: /// \cond HIDDEN_SYMBOLS - Int_t WriteObject(void *obj, const char* name, Option_t *option="", Int_t bufsize=0); // Intentionally not implemented. + Int_t WriteObject(void *obj, const char* name, Option_t *option="", Long64_t bufsize=0); // Intentionally not implemented. /// \endcond public: /// \brief Write an object with proper type checking. @@ -280,7 +280,7 @@ can be replaced with the simpler and exception safe: /// from TObject. The method redirects to TDirectory::WriteObjectAny. template inline std::enable_if_t::value, Int_t> - WriteObject(const T *obj, const char *name, Option_t *option = "", Int_t bufsize = 0) + WriteObject(const T *obj, const char *name, Option_t *option = "", Long64_t bufsize = 0) { return WriteObjectAny(obj, TClass::GetClass(), name, option, bufsize); } @@ -294,12 +294,12 @@ can be replaced with the simpler and exception safe: /// TObject. The method redirects to TDirectory::WriteTObject. template inline std::enable_if_t::value, Int_t> - WriteObject(const T *obj, const char *name, Option_t *option = "", Int_t bufsize = 0) + WriteObject(const T *obj, const char *name, Option_t *option = "", Long64_t bufsize = 0) { return WriteTObject(obj, name, option, bufsize); } - virtual Int_t WriteObjectAny(const void *, const char * /*classname*/, const char * /*name*/, Option_t * /*option*/="", Int_t /*bufsize*/ =0) {return 0;} - virtual Int_t WriteObjectAny(const void *, const TClass * /*cl*/, const char * /*name*/, Option_t * /*option*/="", Int_t /*bufsize*/ =0) {return 0;} + virtual Int_t WriteObjectAny(const void *, const char * /*classname*/, const char * /*name*/, Option_t * /*option*/="", Long64_t /*bufsize*/ =0) {return 0;} + virtual Int_t WriteObjectAny(const void *, const TClass * /*cl*/, const char * /*name*/, Option_t * /*option*/="", Long64_t /*bufsize*/ =0) {return 0;} virtual void WriteDirHeader() {} virtual void WriteKeys() {} diff --git a/core/base/inc/TObject.h b/core/base/inc/TObject.h index 456c21ad10fc3..d3529f18c6919 100644 --- a/core/base/inc/TObject.h +++ b/core/base/inc/TObject.h @@ -172,8 +172,8 @@ class TObject { virtual void SetDrawOption(Option_t *option=""); // *MENU* virtual void SetUniqueID(UInt_t uid); virtual void UseCurrentStyle(); - virtual Int_t Write(const char *name = nullptr, Int_t option = 0, Int_t bufsize = 0); - virtual Int_t Write(const char *name = nullptr, Int_t option = 0, Int_t bufsize = 0) const; + virtual Int_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0); + virtual Int_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const; /// IsDestructed /// diff --git a/core/base/src/TBuffer.cxx b/core/base/src/TBuffer.cxx index 8a0c2b78e99e6..0a27db1c284c4 100644 --- a/core/base/src/TBuffer.cxx +++ b/core/base/src/TBuffer.cxx @@ -69,10 +69,10 @@ TBuffer::TBuffer(EMode mode) /// Create an I/O buffer object. Mode should be either TBuffer::kRead or /// TBuffer::kWrite. -TBuffer::TBuffer(EMode mode, Int_t bufsize) +TBuffer::TBuffer(EMode mode, Long64_t bufsize) { - if (bufsize < 0) - Fatal("TBuffer","Request to create a buffer with a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", bufsize, kMaxBufferSize); + if (bufsize > kMaxBufferSize) + Fatal("TBuffer","Request to create a too large buffer: 0x%llx for a max of 0x%x.", bufsize, kMaxBufferSize); if (bufsize < kMinimalSize) bufsize = kMinimalSize; fBufSize = bufsize; fMode = mode; @@ -100,10 +100,10 @@ TBuffer::TBuffer(EMode mode, Int_t bufsize) /// is provided, a Fatal error will be issued if the Buffer attempts to /// expand. -TBuffer::TBuffer(EMode mode, Int_t bufsize, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc) +TBuffer::TBuffer(EMode mode, Long64_t bufsize, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc) { - if (bufsize < 0) - Fatal("TBuffer","Request to create a buffer with a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", bufsize, kMaxBufferSize); + if (bufsize > kMaxBufferSize) + Fatal("TBuffer","Request to create a too large buffer: 0x%llx for a max of 0x%x.", bufsize, kMaxBufferSize); fBufSize = bufsize; fMode = mode; fVersion = 0; @@ -154,10 +154,10 @@ TBuffer::~TBuffer() /// If the size_needed is larger than the current size, the policy /// is to expand to double the current size or the size_needed which ever is largest. -void TBuffer::AutoExpand(Int_t size_needed) +void TBuffer::AutoExpand(Long64_t size_needed) { - if (size_needed < 0) { - Fatal("AutoExpand","Request to expand to a negative size, likely due to an integer overflow: 0x%x for a max of 0x%x.", size_needed, kMaxBufferSize); + if (size_needed > kMaxBufferSize) { + Fatal("AutoExpand","Request to expand a too large buffer: 0x%llx for a max of 0x%x.", size_needed, kMaxBufferSize); } if (size_needed > fBufSize) { Long64_t doubling = 2LLU * fBufSize; @@ -183,8 +183,10 @@ void TBuffer::AutoExpand(Int_t size_needed) /// is provided, a Fatal error will be issued if the Buffer attempts to /// expand. -void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocCharFun_t reallocfunc) +void TBuffer::SetBuffer(void *buf, Long64_t newsiz, Bool_t adopt, ReAllocCharFun_t reallocfunc) { + if (newsiz > kMaxBufferSize) + Fatal("SetBuffer","Request to create a too large buffer: 0x%llx for a max of 0x%x.", newsiz, kMaxBufferSize); if (fBuffer && TestBit(kIsOwner)) delete [] fBuffer; @@ -219,19 +221,19 @@ void TBuffer::SetBuffer(void *buf, UInt_t newsiz, Bool_t adopt, ReAllocCharFun_t /// In order to avoid losing data, if the current length is greater than /// the requested size, we only shrink down to the current length. -void TBuffer::Expand(Int_t newsize, Bool_t copy) +void TBuffer::Expand(Long64_t newsize, Bool_t copy) { Int_t l = Length(); - if ( (l > newsize) && copy ) { + if ( (Long64_t(l) > newsize) && copy ) { newsize = l; } const Int_t extraspace = (fMode&kWrite)!=0 ? kExtraSpace : 0; - if ( ((Long64_t)newsize+extraspace) > kMaxBufferSize) { + if ( newsize > kMaxBufferSize - kExtraSpace) { if (l < kMaxBufferSize) { newsize = kMaxBufferSize - extraspace; } else { - Fatal("Expand","Requested size (%d) is too large (max is %d).", newsize, kMaxBufferSize); + Fatal("Expand","Requested size (%lld) is too large (max is %d).", newsize, kMaxBufferSize); } } if ( (fMode&kWrite)!=0 ) { diff --git a/core/base/src/TDirectory.cxx b/core/base/src/TDirectory.cxx index 9bebee0e74a1d..cc49cb16917da 100644 --- a/core/base/src/TDirectory.cxx +++ b/core/base/src/TDirectory.cxx @@ -342,11 +342,12 @@ static TBuffer* R__CreateBuffer() if (!creator) { R__LOCKGUARD(gROOTMutex); TClass *c = TClass::GetClass("TBufferFile"); - TMethod *m = c->GetMethodWithPrototype("TBufferFile","TBuffer::EMode,Int_t",kFALSE,ROOT::kExactMatch); + TMethod *m = c->GetMethodWithPrototype("TBufferFile","TBuffer::EMode,Long64_t",kFALSE,ROOT::kExactMatch); + assert(m != nullptr); creator = (tcling_callfunc_Wrapper_t)( m->InterfaceMethod() ); } TBuffer::EMode mode = TBuffer::kWrite; - Int_t size = 10000; + Long64_t size = 10000; void *args[] = { &mode, &size }; TBuffer *result; creator(nullptr,2,args,&result); @@ -1423,9 +1424,9 @@ void TDirectory::RegisterGDirectory(TDirectory::SharedGDirectory_t &gdirectory_p } //////////////////////////////////////////////////////////////////////////////// -/// \copydoc TDirectoryFile::WriteObject(const T*,const char*,Option_t*,Int_t). +/// \copydoc TDirectoryFile::WriteObject(const T*,const char*,Option_t*,Long64_t). -Int_t TDirectory::WriteTObject(const TObject *obj, const char *name, Option_t * /*option*/, Int_t /*bufsize*/) +Int_t TDirectory::WriteTObject(const TObject *obj, const char *name, Option_t * /*option*/, Long64_t /*bufsize*/) { const char *objname = "no name specified"; if (name) objname = name; diff --git a/core/base/src/TObject.cxx b/core/base/src/TObject.cxx index 3decd1db81926..033e098b5aaed 100644 --- a/core/base/src/TObject.cxx +++ b/core/base/src/TObject.cxx @@ -956,7 +956,7 @@ void TObject::UseCurrentStyle() /// The function returns the total number of bytes written to the file. /// It returns 0 if the object cannot be written. -Int_t TObject::Write(const char *name, Int_t option, Int_t bufsize) const +Int_t TObject::Write(const char *name, Int_t option, Long64_t bufsize) const { if (R__unlikely(option & kOnlyPrepStep)) return 0; @@ -978,7 +978,7 @@ Int_t TObject::Write(const char *name, Int_t option, Int_t bufsize) const /// Write this object to the current directory. For more see the /// const version of this method. -Int_t TObject::Write(const char *name, Int_t option, Int_t bufsize) +Int_t TObject::Write(const char *name, Int_t option, Long64_t bufsize) { return ((const TObject*)this)->Write(name, option, bufsize); } diff --git a/core/cont/inc/TCollection.h b/core/cont/inc/TCollection.h index 65f6c7f72af92..830a483c66079 100644 --- a/core/cont/inc/TCollection.h +++ b/core/cont/inc/TCollection.h @@ -208,8 +208,8 @@ class TCollection : public TObject { void SetName(const char *name) { fName = name; } virtual void SetOwner(Bool_t enable = kTRUE); virtual bool UseRWLock(Bool_t enable = true); - Int_t Write(const char *name = nullptr, Int_t option = 0, Int_t bufsize = 0) override; - Int_t Write(const char *name = nullptr, Int_t option = 0, Int_t bufsize = 0) const override; + Int_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0) override; + Int_t Write(const char *name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const override; R__ALWAYS_INLINE Bool_t IsUsingRWLock() const { return TestBit(TCollection::kUseRWLock); } diff --git a/core/cont/inc/TMap.h b/core/cont/inc/TMap.h index 6243060846119..d40de95a68564 100644 --- a/core/cont/inc/TMap.h +++ b/core/cont/inc/TMap.h @@ -85,8 +85,8 @@ friend class TMapIter; TPair *RemoveEntry(TObject *key); virtual void SetOwnerValue(Bool_t enable = kTRUE); virtual void SetOwnerKeyValue(Bool_t ownkeys = kTRUE, Bool_t ownvals = kTRUE); - Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override; - Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) const override; + Int_t Write(const char *name=nullptr, Int_t option=0, Long64_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t option=0, Long64_t bufsize=0) const override; ClassDefOverride(TMap,3) //A (key,value) map }; diff --git a/core/cont/src/TCollection.cxx b/core/cont/src/TCollection.cxx index 81fe664eea6fb..33378c4d7774c 100644 --- a/core/cont/src/TCollection.cxx +++ b/core/cont/src/TCollection.cxx @@ -676,7 +676,7 @@ void TCollection::Streamer(TBuffer &b) /// objects using a single key specify a name and set option to /// TObject::kSingleKey (i.e. 1). -Int_t TCollection::Write(const char *name, Int_t option, Int_t bufsize) const +Int_t TCollection::Write(const char *name, Int_t option, Long64_t bufsize) const { if ((option & kSingleKey)) { return TObject::Write(name, option, bufsize); @@ -700,7 +700,7 @@ Int_t TCollection::Write(const char *name, Int_t option, Int_t bufsize) const /// objects using a single key specify a name and set option to /// TObject::kSingleKey (i.e. 1). -Int_t TCollection::Write(const char *name, Int_t option, Int_t bufsize) +Int_t TCollection::Write(const char *name, Int_t option, Long64_t bufsize) { return ((const TCollection*)this)->Write(name,option,bufsize); } diff --git a/core/cont/src/TMap.cxx b/core/cont/src/TMap.cxx index a1af3bac25490..338e636a7b1a0 100644 --- a/core/cont/src/TMap.cxx +++ b/core/cont/src/TMap.cxx @@ -401,7 +401,7 @@ void TMap::Streamer(TBuffer &b) /// objects using a single key specify a name and set option to /// TObject::kSingleKey (i.e. 1). -Int_t TMap::Write(const char *name, Int_t option, Int_t bufsize) const +Int_t TMap::Write(const char *name, Int_t option, Long64_t bufsize) const { if ((option & kSingleKey)) { return TObject::Write(name, option, bufsize); @@ -428,7 +428,7 @@ Int_t TMap::Write(const char *name, Int_t option, Int_t bufsize) const /// objects using a single key specify a name and set option to /// TObject::kSingleKey (i.e. 1). -Int_t TMap::Write(const char *name, Int_t option, Int_t bufsize) +Int_t TMap::Write(const char *name, Int_t option, Long64_t bufsize) { return ((const TMap*)this)->Write(name,option,bufsize); } diff --git a/hist/hbook/inc/THbookBranch.h b/hist/hbook/inc/THbookBranch.h index ef5881462aae4..70e4cbbbb8958 100644 --- a/hist/hbook/inc/THbookBranch.h +++ b/hist/hbook/inc/THbookBranch.h @@ -30,8 +30,8 @@ class THbookBranch : public TBranch { public: THbookBranch() {} - THbookBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - THbookBranch(TBranch *branch, const char *name, void *address, const char *leaflist, Int_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + THbookBranch(TTree *tree, const char *name, void *address, const char *leaflist, Long64_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + THbookBranch(TBranch *branch, const char *name, void *address, const char *leaflist, Long64_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); ~THbookBranch() override; void Browse(TBrowser *b) override; Int_t GetEntry(Long64_t entry=0, Int_t getall=0) override; diff --git a/hist/hbook/src/THbookBranch.cxx b/hist/hbook/src/THbookBranch.cxx index a8e8f26140ff9..97d67e1759c6d 100644 --- a/hist/hbook/src/THbookBranch.cxx +++ b/hist/hbook/src/THbookBranch.cxx @@ -21,14 +21,14 @@ //////////////////////////////////////////////////////////////////////////////// -THbookBranch::THbookBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize, Int_t compress) +THbookBranch::THbookBranch(TTree *tree, const char *name, void *address, const char *leaflist, Long64_t basketsize, Int_t compress) :TBranch(tree, name,address,leaflist,basketsize,compress) { } //////////////////////////////////////////////////////////////////////////////// -THbookBranch::THbookBranch(TBranch *branch, const char *name, void *address, const char *leaflist, Int_t basketsize, Int_t compress) +THbookBranch::THbookBranch(TBranch *branch, const char *name, void *address, const char *leaflist, Long64_t basketsize, Int_t compress) :TBranch(branch,name,address,leaflist,basketsize,compress) { } diff --git a/hist/hbook/src/THbookFile.cxx b/hist/hbook/src/THbookFile.cxx index 5ea121775313d..917a590360735 100644 --- a/hist/hbook/src/THbookFile.cxx +++ b/hist/hbook/src/THbookFile.cxx @@ -769,7 +769,7 @@ TObject *THbookFile::ConvertCWN(Int_t id) } - Int_t bufsize = 8000; + Long64_t bufsize = 8000; THbookBranch *branch = new THbookBranch(tree,name,(void*)&bigbuf[bufpos],fullname,bufsize); tree->GetListOfBranches()->Add(branch); branch->SetBlockName(block); diff --git a/hist/hist/inc/TH1.h b/hist/hist/inc/TH1.h index 8cce4f6fc0261..862d4860ba973 100644 --- a/hist/hist/inc/TH1.h +++ b/hist/hist/inc/TH1.h @@ -627,13 +627,13 @@ class TH1 : public TNamed, public TAttLine, public TAttFill, public TAttMarker { const Double_t *zBins); virtual void SetBinsLength(Int_t = -1) { } //redefined in derived classes virtual void SetBinErrorOption(EBinErrorOpt type) { fBinStatErrOpt = type; } - virtual void SetBuffer(Int_t bufsize, Option_t *option=""); + virtual void SetBuffer(Long64_t bufsize, Option_t *option=""); virtual UInt_t SetCanExtend(UInt_t extendBitMask); virtual void SetContent(const Double_t *content); virtual void SetContour(Int_t nlevels, const Double_t *levels = nullptr); virtual void SetContourLevel(Int_t level, Double_t value); virtual void SetColors(Color_t linecolor = -1, Color_t markercolor = -1, Color_t fillcolor = -1); - static void SetDefaultBufferSize(Int_t bufsize=1000); + static void SetDefaultBufferSize(Long64_t bufsize=1000); static void SetDefaultSumw2(Bool_t sumw2=kTRUE); virtual void SetDirectory(TDirectory *dir); virtual void SetEntries(Double_t n) { fEntries = n; } diff --git a/hist/hist/inc/TProfile.h b/hist/hist/inc/TProfile.h index e1b00a80bd4b2..316f61f3d2eb3 100644 --- a/hist/hist/inc/TProfile.h +++ b/hist/hist/inc/TProfile.h @@ -132,7 +132,7 @@ class TProfile : public TH1D { void SetBins(Int_t nbins, Double_t xmin, Double_t xmax) override; void SetBins(Int_t nx, const Double_t *xbins) override; void SetBinsLength(Int_t n=-1) override; - void SetBuffer(Int_t bufsize, Option_t *option="") override; + void SetBuffer(Long64_t bufsize, Option_t *option="") override; virtual void SetErrorOption(Option_t *option=""); // *MENU* void Sumw2(Bool_t flag = kTRUE) override; diff --git a/hist/hist/inc/TProfile2D.h b/hist/hist/inc/TProfile2D.h index 564141207c4f3..5215608e2dd30 100644 --- a/hist/hist/inc/TProfile2D.h +++ b/hist/hist/inc/TProfile2D.h @@ -146,7 +146,7 @@ class TProfile2D : public TH2D { void SetBins(Int_t nbinsx, Double_t xmin, Double_t xmax, Int_t nbinsy, Double_t ymin, Double_t ymax) override; void SetBins(Int_t nx, const Double_t *xBins, Int_t ny, const Double_t *yBins) override; void SetBinsLength(Int_t n=-1) override; - void SetBuffer(Int_t bufsize, Option_t *option="") override; + void SetBuffer(Long64_t bufsize, Option_t *option="") override; virtual void SetErrorOption(Option_t *option=""); // *MENU* void Sumw2(Bool_t flag = kTRUE) override; Double_t GetNumberOfBins() { return fBinEntries.GetSize(); } diff --git a/hist/hist/inc/TProfile3D.h b/hist/hist/inc/TProfile3D.h index 1b82c6c5d2d89..6779bf69e1c64 100644 --- a/hist/hist/inc/TProfile3D.h +++ b/hist/hist/inc/TProfile3D.h @@ -144,7 +144,7 @@ class TProfile3D : public TH3D { void SetBins(Int_t nx, const Double_t *xBins, Int_t ny, const Double_t * yBins, Int_t nz, const Double_t *zBins) override; void SetBinsLength(Int_t n=-1) override; - void SetBuffer(Int_t bufsize, Option_t *opt="") override; + void SetBuffer(Long64_t bufsize, Option_t *opt="") override; virtual void SetErrorOption(Option_t *option=""); // *MENU* void Sumw2(Bool_t flag = kTRUE) override; diff --git a/hist/hist/src/TH1.cxx b/hist/hist/src/TH1.cxx index 168cfd0a4afa6..0db6b59c3a7b0 100644 --- a/hist/hist/src/TH1.cxx +++ b/hist/hist/src/TH1.cxx @@ -6745,8 +6745,9 @@ UInt_t TH1::GetAxisLabelStatus() const /// or equal to its upper limit, the function SetBuffer is automatically /// called with the default buffer size. -void TH1::SetDefaultBufferSize(Int_t bufsize) +void TH1::SetDefaultBufferSize(Long64_t bufsize) { + assert(bufsize <= kMaxInt); fgBufferSize = bufsize > 0 ? bufsize : 0; } @@ -8513,7 +8514,7 @@ Double_t TH1::GetContourLevelPad(Int_t level) const //////////////////////////////////////////////////////////////////////////////// /// Set the maximum number of entries to be kept in the buffer. -void TH1::SetBuffer(Int_t bufsize, Option_t * /*option*/) +void TH1::SetBuffer(Long64_t bufsize, Option_t * /*option*/) { if (fBuffer) { BufferEmpty(); @@ -8525,6 +8526,8 @@ void TH1::SetBuffer(Int_t bufsize, Option_t * /*option*/) return; } if (bufsize < 100) bufsize = 100; + if (1 + bufsize*(fDimension+1)> kMaxInt) + Fatal("SetBufferSize", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", 1 + bufsize*(fDimension+1), kMaxInt); fBufferSize = 1 + bufsize*(fDimension+1); fBuffer = new Double_t[fBufferSize]; memset(fBuffer, 0, sizeof(Double_t)*fBufferSize); diff --git a/hist/hist/src/TProfile.cxx b/hist/hist/src/TProfile.cxx index 4885ed630f111..4583f1c6362c4 100644 --- a/hist/hist/src/TProfile.cxx +++ b/hist/hist/src/TProfile.cxx @@ -1770,7 +1770,7 @@ void TProfile::SetBinsLength(Int_t n) //////////////////////////////////////////////////////////////////////////////// /// Set the buffer size in units of 8 bytes (double). -void TProfile::SetBuffer(Int_t bufsize, Option_t *) +void TProfile::SetBuffer(Long64_t bufsize, Option_t *) { if (fBuffer) { BufferEmpty(); @@ -1782,6 +1782,8 @@ void TProfile::SetBuffer(Int_t bufsize, Option_t *) return; } if (bufsize < 100) bufsize = 100; + if (1 + 3*bufsize > kMaxInt) + Fatal("SetBufferSize", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", 1 + 3*bufsize, kMaxInt); fBufferSize = 1 + 3*bufsize; fBuffer = new Double_t[fBufferSize]; memset(fBuffer,0,sizeof(Double_t)*fBufferSize); diff --git a/hist/hist/src/TProfile2D.cxx b/hist/hist/src/TProfile2D.cxx index 09e6700e8989e..cfa6c8c6d23ef 100644 --- a/hist/hist/src/TProfile2D.cxx +++ b/hist/hist/src/TProfile2D.cxx @@ -2022,7 +2022,7 @@ void TProfile2D::SetBinsLength(Int_t n) //////////////////////////////////////////////////////////////////////////////// /// Set the buffer size in units of 8 bytes (double). -void TProfile2D::SetBuffer(Int_t bufsize, Option_t *) +void TProfile2D::SetBuffer(Long64_t bufsize, Option_t *) { if (fBuffer) { BufferEmpty(); @@ -2034,6 +2034,8 @@ void TProfile2D::SetBuffer(Int_t bufsize, Option_t *) return; } if (bufsize < 100) bufsize = 100; + if (1 + 4*bufsize > kMaxInt) + Fatal("SetBufferSize", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", 1 + 4*bufsize, kMaxInt); fBufferSize = 1 + 4*bufsize; fBuffer = new Double_t[fBufferSize]; memset(fBuffer,0,sizeof(Double_t)*fBufferSize); diff --git a/hist/hist/src/TProfile3D.cxx b/hist/hist/src/TProfile3D.cxx index 4756da07a4778..32b9e6b6847e0 100644 --- a/hist/hist/src/TProfile3D.cxx +++ b/hist/hist/src/TProfile3D.cxx @@ -1391,7 +1391,7 @@ void TProfile3D::SetBinsLength(Int_t n) //////////////////////////////////////////////////////////////////////////////// /// Set the buffer size in units of 8 bytes (double). -void TProfile3D::SetBuffer(Int_t bufsize, Option_t *) +void TProfile3D::SetBuffer(Long64_t bufsize, Option_t *) { if (fBuffer) { BufferEmpty(); @@ -1403,6 +1403,8 @@ void TProfile3D::SetBuffer(Int_t bufsize, Option_t *) return; } if (bufsize < 100) bufsize = 100; + if (1 + 5*bufsize > kMaxInt) + Fatal("SetBufferSize", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", 1 + 5*bufsize, kMaxInt); fBufferSize = 1 + 5*bufsize; fBuffer = new Double_t[fBufferSize]; memset(fBuffer,0,sizeof(Double_t)*fBufferSize); diff --git a/hist/hist/src/TScatter.cxx b/hist/hist/src/TScatter.cxx index dfec152176360..5c2b6a573135b 100644 --- a/hist/hist/src/TScatter.cxx +++ b/hist/hist/src/TScatter.cxx @@ -83,6 +83,9 @@ TScatter::TScatter(Int_t n, const Double_t *x, const Double_t *y, const Double_t fMaxSize = fGraph->GetMaxSize(); Int_t bufsize = sizeof(Double_t) * fNpoints; + if (sizeof(Double_t) * fNpoints > kMaxInt || bufsize < 0) { + Fatal("TScatter", "Negative buffer size likely due to an integer overflow: 0x%x.", bufsize); + } if (col) { fColor = new Double_t[fMaxSize]; memcpy(fColor, col, bufsize); diff --git a/hist/histpainter/src/TPainter3dAlgorithms.cxx b/hist/histpainter/src/TPainter3dAlgorithms.cxx index f0884c9aa3656..7a4f7f8fb4595 100644 --- a/hist/histpainter/src/TPainter3dAlgorithms.cxx +++ b/hist/histpainter/src/TPainter3dAlgorithms.cxx @@ -2009,7 +2009,9 @@ void TPainter3dAlgorithms::InitRaster(Double_t xmin, Double_t ymin, Double_t xma fDYrast = ymax - ymin; // Create buffer for raster - Int_t bufsize = nx*ny/30 + 1; + if (Long64_t(nx)*ny / 30 + 1 > kMaxInt) + Fatal("InitRaster", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", Long64_t(nx)*ny / 30 + 1, kMaxInt); + Int_t bufsize = Long64_t(nx)*ny/30 + 1; fRaster.resize(bufsize); // S E T M A S K S diff --git a/io/io/inc/ROOT/TBufferMerger.hxx b/io/io/inc/ROOT/TBufferMerger.hxx index d3c8ac86849a2..09fd41d58e802 100644 --- a/io/io/inc/ROOT/TBufferMerger.hxx +++ b/io/io/inc/ROOT/TBufferMerger.hxx @@ -172,7 +172,7 @@ public: * This function must be called before the TBufferMergerFile gets destroyed, * or no data is appended to the TBufferMerger. */ - Int_t Write(const char *name = nullptr, Int_t opt = 0, Int_t bufsize = 0) override; + Int_t Write(const char *name = nullptr, Int_t opt = 0, Long64_t bufsize = 0) override; ClassDefOverride(TBufferMergerFile, 0); }; diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 5aaf5f1916f83..3d2e37141fcc4 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -59,9 +59,9 @@ class TBufferFile : public TBufferIO { TBufferFile(const TBufferFile &) = delete; ///< not implemented void operator=(const TBufferFile &) = delete; ///< not implemented - Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss, const char* classname); - void CheckCount(UInt_t offset) override; - UInt_t CheckObject(UInt_t offset, const TClass *cl, Bool_t readClass = kFALSE); + Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char* classname); + void CheckCount(UInt_t offset) override; + UInt_t CheckObject(UInt_t offset, const TClass *cl, Bool_t readClass = kFALSE); void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse) override; @@ -69,13 +69,13 @@ class TBufferFile : public TBufferIO { enum { kStreamedMemberWise = BIT(14) }; //added to version number to know if a collection has been stored member-wise TBufferFile(TBuffer::EMode mode); - TBufferFile(TBuffer::EMode mode, Int_t bufsize); - TBufferFile(TBuffer::EMode mode, Int_t bufsize, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); + TBufferFile(TBuffer::EMode mode, Long64_t bufsize); + TBufferFile(TBuffer::EMode mode, Long64_t bufsize, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); ~TBufferFile() override; - Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss) override; - Int_t CheckByteCount(UInt_t startpos, UInt_t bcnt, const char *classname) override; - void SetByteCount(UInt_t cntpos, Bool_t packInVersion = kFALSE) override; + Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss) override; + Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const char *classname) override; + void SetByteCount(ULong64_t cntpos, Bool_t packInVersion = kFALSE) override; void SkipVersion(const TClass *cl = nullptr) override; Version_t ReadVersion(UInt_t *start = nullptr, UInt_t *bcnt = nullptr, const TClass *cl = nullptr) override; @@ -95,10 +95,10 @@ class TBufferFile : public TBufferIO { void ClassEnd(const TClass*) override {} void ClassMember(const char*, const char * = nullptr, Int_t = -1, Int_t = -1) override {} - Int_t ReadBuf(void *buf, Int_t max) override; - void WriteBuf(const void *buf, Int_t max) override; + Long64_t ReadBuf(void *buf, Long64_t max) override; + void WriteBuf(const void *buf, Long64_t max) override; - char *ReadString(char *s, Int_t max) override; + char *ReadString(char *s, Long64_t max) override; void WriteString(const char *s) override; TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) override; diff --git a/io/io/inc/TBufferIO.h b/io/io/inc/TBufferIO.h index 1500beed2616e..eeec87582d007 100644 --- a/io/io/inc/TBufferIO.h +++ b/io/io/inc/TBufferIO.h @@ -25,6 +25,8 @@ #include "TString.h" +#include + class TExMap; class TBufferIO : public TBuffer { @@ -44,8 +46,8 @@ class TBufferIO : public TBuffer { TBufferIO() {} // NOLINT: not allowed to use = default because of TObject::kIsOnHeap detection, see ROOT-10300 TBufferIO(TBuffer::EMode mode); - TBufferIO(TBuffer::EMode mode, Int_t bufsize); - TBufferIO(TBuffer::EMode mode, Int_t bufsize, void *buf, Bool_t adopt = kTRUE, + TBufferIO(TBuffer::EMode mode, Long64_t bufsize); + TBufferIO(TBuffer::EMode mode, Long64_t bufsize, void *buf, Bool_t adopt = kTRUE, ReAllocCharFun_t reallocfunc = nullptr); //////////////////////////////////////////////////////////////////////////////// @@ -80,7 +82,7 @@ class TBufferIO : public TBuffer { void SetPidOffset(UShort_t offset) override; Int_t GetBufferDisplacement() const override { return fDisplacement; } void SetBufferDisplacement() override { fDisplacement = 0; } - void SetBufferDisplacement(Int_t skipped) override { fDisplacement = (Int_t)(Length() - skipped); } + void SetBufferDisplacement(Long64_t skipped) override { assert(skipped <= kMaxInt); fDisplacement = (Int_t)(Length() - skipped); } // Utilities for objects map void SetReadParam(Int_t mapsize) override; @@ -89,8 +91,8 @@ class TBufferIO : public TBuffer { void ResetMap() override; void Reset() override; Int_t GetMapCount() const override { return fMapCount; } - void MapObject(const TObject *obj, UInt_t offset = 1) override; - void MapObject(const void *obj, const TClass *cl, UInt_t offset = 1) override; + void MapObject(const TObject *obj, ULong64_t offset = 1) override; + void MapObject(const void *obj, const TClass *cl, ULong64_t offset = 1) override; Bool_t CheckObject(const TObject *obj) override; Bool_t CheckObject(const void *obj, const TClass *ptrClass) override; void GetMappedObject(UInt_t tag, void *&ptr, TClass *&ClassPtr) const override; @@ -98,8 +100,8 @@ class TBufferIO : public TBuffer { // Utilities for TStreamerInfo void ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t force) override; void ForceWriteInfoClones(TClonesArray *a) override; - Int_t ReadClones(TClonesArray *a, Int_t nobjects, Version_t objvers) override; - Int_t WriteClones(TClonesArray *a, Int_t nobjects) override; + Int_t ReadClones(TClonesArray *a, Long64_t nobjects, Version_t objvers) override; + Int_t WriteClones(TClonesArray *a, Long64_t nobjects) override; void TagStreamerInfo(TVirtualStreamerInfo *info) override; // Special basic ROOT objects and collections diff --git a/io/io/inc/TBufferText.h b/io/io/inc/TBufferText.h index e19cd7ca8d0e6..a5cbffc99deb0 100644 --- a/io/io/inc/TBufferText.h +++ b/io/io/inc/TBufferText.h @@ -75,20 +75,20 @@ class TBufferText : public TBufferIO { // virtual abstract TBuffer methods, which are not used in text streaming - Int_t CheckByteCount(UInt_t /* startpos */, UInt_t /* bcnt */, const TClass * /* clss */) final { return 0; } - Int_t CheckByteCount(UInt_t /* startpos */, UInt_t /* bcnt */, const char * /* classname */) final { return 0; } - void SetByteCount(UInt_t /* cntpos */, Bool_t /* packInVersion */ = kFALSE) final {} + Long64_t CheckByteCount(ULong64_t /* startpos */, ULong64_t /* bcnt */, const TClass * /* clss */) final { return 0; } + Long64_t CheckByteCount(ULong64_t /* startpos */, ULong64_t /* bcnt */, const char * /* classname */) final { return 0; } + void SetByteCount(ULong64_t /* cntpos */, Bool_t /* packInVersion */ = kFALSE) final {} void SkipVersion(const TClass *cl = nullptr) final; Version_t ReadVersionNoCheckSum(UInt_t *, UInt_t *) final { return 0; } - Int_t ReadBuf(void * /*buf*/, Int_t /*max*/) final + Long64_t ReadBuf(void * /*buf*/, Long64_t /*max*/) final { Error("ReadBuf", "useless in text streamers"); return 0; } - void WriteBuf(const void * /*buf*/, Int_t /*max*/) final { Error("WriteBuf", "useless in text streamers"); } + void WriteBuf(const void * /*buf*/, Long64_t /*max*/) final { Error("WriteBuf", "useless in text streamers"); } - char *ReadString(char * /*s*/, Int_t /*max*/) final + char *ReadString(char * /*s*/, Long64_t /*max*/) final { Error("ReadString", "useless"); return nullptr; diff --git a/io/io/inc/TDirectoryFile.h b/io/io/inc/TDirectoryFile.h index 16f2d2edaa4e4..d09720d4b7662 100644 --- a/io/io/inc/TDirectoryFile.h +++ b/io/io/inc/TDirectoryFile.h @@ -114,17 +114,17 @@ class TDirectoryFile : public TDirectory { void Save() override; void SaveSelf(Bool_t force = kFALSE) override; Int_t SaveObjectAs(const TObject *obj, const char *filename="", Option_t *option="") const override; - void SetBufferSize(Int_t bufsize) override; + void SetBufferSize(Long64_t bufsize) override; void SetModified() override {fModified = kTRUE;} void SetSeekDir(Long64_t v) override { fSeekDir = v; } void SetTRefAction(TObject *ref, TObject *parent) override; void SetWritable(Bool_t writable=kTRUE) override; Int_t Sizeof() const override; - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override; - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) const override; - Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *option="", Int_t bufsize=0) override; - Int_t WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option="", Int_t bufsize=0) override; - Int_t WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option="", Int_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) const override; + Int_t WriteTObject(const TObject *obj, const char *name=nullptr, Option_t *option="", Long64_t bufsize=0) override; + Int_t WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option="", Long64_t bufsize=0) override; + Int_t WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option="", Long64_t bufsize=0) override; void WriteDirHeader() override; void WriteKeys() override; diff --git a/io/io/inc/TFile.h b/io/io/inc/TFile.h index b70cdcc28e988..73dfc7f026002 100644 --- a/io/io/inc/TFile.h +++ b/io/io/inc/TFile.h @@ -285,10 +285,10 @@ class TFile : public TDirectoryFile { void Close(Option_t *option="") override; // *MENU* void Copy(TObject &) const override { MayNotUse("Copy(TObject &)"); } - virtual Bool_t Cp(const char *dst, Bool_t progressbar = kTRUE,UInt_t bufsize = 1000000); - virtual TKey* CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize); + virtual Bool_t Cp(const char *dst, Bool_t progressbar = kTRUE, Long64_t bufsize = 1000000); + virtual TKey* CreateKey(TDirectory* mother, const TObject* obj, const char* name, Long64_t bufsize); virtual TKey* CreateKey(TDirectory* mother, const void* obj, const TClass* cl, - const char* name, Int_t bufsize); + const char* name, Long64_t bufsize); static TFile *&CurrentFile(); // Return the current file for this thread. void Delete(const char *namecycle="") override; void Draw(Option_t *option="") override; @@ -372,10 +372,10 @@ class TFile : public TDirectoryFile { virtual void SetReadCalls(Int_t readcalls = 0) { fReadCalls = readcalls; } virtual void ShowStreamerInfo(); Int_t Sizeof() const override; - void SumBuffer(Int_t bufsize); + void SumBuffer(Long64_t bufsize); virtual Bool_t WriteBuffer(const char *buf, Int_t len); - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override; - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) const override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) const override; virtual void WriteFree(); virtual void WriteHeader(); virtual UShort_t WriteProcessID(TProcessID *pid); @@ -403,8 +403,8 @@ class TFile : public TDirectoryFile { static void SetFileBytesRead(Long64_t bytes = 0); static void SetFileBytesWritten(Long64_t bytes = 0); - static void SetFileReadCalls(Int_t readcalls = 0); - static void SetReadaheadSize(Int_t bufsize = 256000); + static void SetFileReadCalls(Long64_t readcalls = 0); + static void SetReadaheadSize(Long64_t bytes = 256000); static void SetReadStreamerInfo(Bool_t readinfo=kTRUE); static Bool_t GetReadStreamerInfo(); @@ -416,7 +416,7 @@ class TFile : public TDirectoryFile { static const char *GetCacheFileDir(); static Bool_t ShrinkCacheFileDir(Long64_t shrinkSize, Long_t cleanupInteval = 0); static Bool_t Cp(const char *src, const char *dst, Bool_t progressbar = kTRUE, - UInt_t buffersize = 1000000); + Long64_t bufsize = 1000000); static UInt_t SetOpenTimeout(UInt_t timeout); // in ms static UInt_t GetOpenTimeout(); // in ms diff --git a/io/io/inc/TFileCacheRead.h b/io/io/inc/TFileCacheRead.h index 0f05c7e8bb199..429bb865dd8ae 100644 --- a/io/io/inc/TFileCacheRead.h +++ b/io/io/inc/TFileCacheRead.h @@ -78,7 +78,7 @@ class TFileCacheRead : public TObject { public: TFileCacheRead(); - TFileCacheRead(TFile *file, Int_t bufsize, TObject *tree = nullptr); + TFileCacheRead(TFile *file, Long64_t bufsize, TObject *tree = nullptr); ~TFileCacheRead() override; virtual Int_t AddBranch(TBranch * /*b*/, Bool_t /*subbranches*/ = kFALSE) { return 0; } virtual Int_t AddBranch(const char * /*branch*/, Bool_t /*subbranches*/ = kFALSE) { return 0; } @@ -107,7 +107,7 @@ class TFileCacheRead : public TObject { virtual Int_t ReadBufferExtNormal(char *buf, Long64_t pos, Int_t len, Int_t &loc); virtual Int_t ReadBufferExtPrefetch(char *buf, Long64_t pos, Int_t len, Int_t &loc); virtual Int_t ReadBuffer(char *buf, Long64_t pos, Int_t len); - virtual Int_t SetBufferSize(Long64_t buffersize); + virtual Int_t SetBufferSize(Long64_t bufsize); virtual void SetFile(TFile *file, TFile::ECacheAction action = TFile::kDisconnect); virtual void SetSkipZip(Bool_t /*skip*/ = kTRUE) {} // This function is only used by TTreeCacheUnzip (ignore it) virtual void Sort(); diff --git a/io/io/inc/TFileCacheWrite.h b/io/io/inc/TFileCacheWrite.h index 83366eabcfc68..e3cce1ab15e1d 100644 --- a/io/io/inc/TFileCacheWrite.h +++ b/io/io/inc/TFileCacheWrite.h @@ -32,7 +32,7 @@ class TFileCacheWrite : public TObject { public: TFileCacheWrite(); - TFileCacheWrite(TFile *file, Int_t bufsize); + TFileCacheWrite(TFile *file, Long64_t bufsize); ~TFileCacheWrite() override; virtual Bool_t Flush(); virtual Int_t GetBytesInCache() const { return fNtot; } diff --git a/io/io/inc/TKey.h b/io/io/inc/TKey.h index a94081326ada1..77635ca9b9242 100644 --- a/io/io/inc/TKey.h +++ b/io/io/inc/TKey.h @@ -52,7 +52,7 @@ class TKey : public TNamed { TDirectory *fMotherDir; ///(fBufCur - fBuffer) + assert( cntpos <= kMaxUInt && (sizeof(UInt_t) + cntpos) < static_cast(fBufCur - fBuffer) && (fBufCur >= fBuffer) && static_cast(fBufCur - fBuffer) <= std::numeric_limits::max() && "Byte count position is after the end of the buffer"); - const UInt_t cnt = UInt_t(fBufCur - fBuffer) - cntpos - sizeof(UInt_t); + const UInt_t cnt = UInt_t(fBufCur - fBuffer) - UInt_t(cntpos) - sizeof(UInt_t); char *buf = (char *)(fBuffer + cntpos); // if true, pack byte count in two consecutive shorts, so it can @@ -358,11 +358,11 @@ void TBufferFile::SetByteCount(UInt_t cntpos, Bool_t packInVersion) /// Returns 0 if everything is ok, otherwise the bytecount offset /// (< 0 when read too little, >0 when read too much). -Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss, const char *classname) +Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char *classname) { if (!bcnt) return 0; - - Int_t offset = 0; + R__ASSERT(startpos <= kMaxUInt && bcnt <= kMaxUInt); + Long64_t offset = 0; Longptr_t endpos = Longptr_t(fBuffer) + startpos + bcnt + sizeof(UInt_t); @@ -373,11 +373,11 @@ Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *cl if (name) { if (offset < 0) { - Error("CheckByteCount", "object of class %s read too few bytes: %d instead of %d", + Error("CheckByteCount", "object of class %s read too few bytes: %lld instead of %llu", name,bcnt+offset,bcnt); } if (offset > 0) { - Error("CheckByteCount", "object of class %s read too many bytes: %d instead of %d", + Error("CheckByteCount", "object of class %s read too many bytes: %lld instead of %llu", name,bcnt+offset,bcnt); if (fParent) Warning("CheckByteCount","%s::Streamer() not in sync with data on file %s, fix Streamer()", @@ -390,7 +390,7 @@ Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *cl if ( ((char *)endpos) > fBufMax ) { offset = fBufMax-fBufCur; Error("CheckByteCount", - "Byte count probably corrupted around buffer position %d:\n\t%d for a possible maximum of %d", + "Byte count probably corrupted around buffer position %llu:\n\t%llu for a possible maximum of %lld", startpos, bcnt, offset); fBufCur = fBufMax; @@ -411,7 +411,7 @@ Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *cl /// Returns 0 if everything is ok, otherwise the bytecount offset /// (< 0 when read too little, >0 when read too much). -Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *clss) +Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss) { if (!bcnt) return 0; return CheckByteCount( startpos, bcnt, clss, nullptr); @@ -425,7 +425,7 @@ Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const TClass *cl /// Returns 0 if everything is ok, otherwise the bytecount offset /// (< 0 when read too little, >0 when read too much). -Int_t TBufferFile::CheckByteCount(UInt_t startpos, UInt_t bcnt, const char *classname) +Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const char *classname) { if (!bcnt) return 0; return CheckByteCount( startpos, bcnt, nullptr, classname); @@ -3332,13 +3332,13 @@ UInt_t TBufferFile::CheckObject(UInt_t offset, const TClass *cl, Bool_t readClas /// Read max bytes from the I/O buffer into buf. The function returns /// the actual number of bytes read. -Int_t TBufferFile::ReadBuf(void *buf, Int_t max) +Long64_t TBufferFile::ReadBuf(void *buf, Long64_t max) { R__ASSERT(IsReading()); if (max == 0) return 0; - Int_t n = std::min(max, (Int_t)(fBufMax - fBufCur)); + Long64_t n = std::min(max, (Long64_t)(fBufMax - fBufCur)); memcpy(buf, fBufCur, n); fBufCur += n; @@ -3349,7 +3349,7 @@ Int_t TBufferFile::ReadBuf(void *buf, Int_t max) //////////////////////////////////////////////////////////////////////////////// /// Write max bytes from buf into the I/O buffer. -void TBufferFile::WriteBuf(const void *buf, Int_t max) +void TBufferFile::WriteBuf(const void *buf, Long64_t max) { R__ASSERT(IsWriting()); @@ -3365,14 +3365,14 @@ void TBufferFile::WriteBuf(const void *buf, Int_t max) /// Read string from I/O buffer. String is read till 0 character is /// found or till max-1 characters are read (i.e. string s has max /// bytes allocated). If max = -1 no check on number of character is -/// made, reading continues till 0 character is found. +/// made, reading continues till 0 character is found or MaxInt-1 chars are read. -char *TBufferFile::ReadString(char *s, Int_t max) +char *TBufferFile::ReadString(char *s, Long64_t max) { R__ASSERT(IsReading()); - + R__ASSERT(max <= kMaxInt); char ch; - Int_t nr = 0; + Long64_t nr = 0; if (max == -1) max = kMaxInt; diff --git a/io/io/src/TBufferIO.cxx b/io/io/src/TBufferIO.cxx index 6e84623c9a56a..30df90184fee7 100644 --- a/io/io/src/TBufferIO.cxx +++ b/io/io/src/TBufferIO.cxx @@ -47,7 +47,7 @@ TBufferIO::TBufferIO(TBuffer::EMode mode) : TBuffer(mode) //////////////////////////////////////////////////////////////////////////////// /// constructor -TBufferIO::TBufferIO(TBuffer::EMode mode, Int_t bufsize) : TBuffer(mode, bufsize) +TBufferIO::TBufferIO(TBuffer::EMode mode, Long64_t bufsize) : TBuffer(mode, bufsize) { fMapSize = fgMapSize; } @@ -55,7 +55,7 @@ TBufferIO::TBufferIO(TBuffer::EMode mode, Int_t bufsize) : TBuffer(mode, bufsize //////////////////////////////////////////////////////////////////////////////// /// constructor -TBufferIO::TBufferIO(TBuffer::EMode mode, Int_t bufsize, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc) +TBufferIO::TBufferIO(TBuffer::EMode mode, Long64_t bufsize, void *buf, Bool_t adopt, ReAllocCharFun_t reallocfunc) : TBuffer(mode, bufsize, buf, adopt, reallocfunc) { fMapSize = fgMapSize; @@ -159,8 +159,9 @@ void TBufferIO::InitMap() /// contains (via via) a pointer to itself. In that case offset must be 1 /// (default value for offset). -void TBufferIO::MapObject(const TObject *obj, UInt_t offset) +void TBufferIO::MapObject(const TObject *obj, ULong64_t offset) { + R__ASSERT(offset <= kMaxUInt); if (IsWriting()) { if (!fMap) InitMap(); @@ -192,8 +193,9 @@ void TBufferIO::MapObject(const TObject *obj, UInt_t offset) /// contains (via via) a pointer to itself. In that case offset must be 1 /// (default value for offset). -void TBufferIO::MapObject(const void *obj, const TClass *cl, UInt_t offset) +void TBufferIO::MapObject(const void *obj, const TClass *cl, ULong64_t offset) { + R__ASSERT(offset <= kMaxUInt); if (IsWriting()) { if (!fMap) InitMap(); @@ -368,8 +370,9 @@ void TBufferIO::TagStreamerInfo(TVirtualStreamerInfo *info) //////////////////////////////////////////////////////////////////////////////// /// Interface to TStreamerInfo::ReadBufferClones. -Int_t TBufferIO::ReadClones(TClonesArray *a, Int_t nobjects, Version_t objvers) +Int_t TBufferIO::ReadClones(TClonesArray *a, Long64_t nobjects, Version_t objvers) { + assert(nobjects <= kMaxInt); char **arr = (char **)a->GetObjectRef(0); char **end = arr + nobjects; // a->GetClass()->GetStreamerInfo()->ReadBufferClones(*this,a,nobjects,-1,0); @@ -381,8 +384,9 @@ Int_t TBufferIO::ReadClones(TClonesArray *a, Int_t nobjects, Version_t objvers) //////////////////////////////////////////////////////////////////////////////// /// Interface to TStreamerInfo::WriteBufferClones. -Int_t TBufferIO::WriteClones(TClonesArray *a, Int_t nobjects) +Int_t TBufferIO::WriteClones(TClonesArray *a, Long64_t nobjects) { + assert(nobjects <= kMaxInt); char **arr = reinterpret_cast(a->GetObjectRef(0)); // a->GetClass()->GetStreamerInfo()->WriteBufferClones(*this,(TClonesArray*)a,nobjects,-1,0); TStreamerInfo *info = (TStreamerInfo *)a->GetClass()->GetStreamerInfo(); diff --git a/io/io/src/TBufferMergerFile.cxx b/io/io/src/TBufferMergerFile.cxx index 951891e2a46ec..63b0b66d379e9 100644 --- a/io/io/src/TBufferMergerFile.cxx +++ b/io/io/src/TBufferMergerFile.cxx @@ -26,7 +26,7 @@ TBufferMergerFile::~TBufferMergerFile() { } -Int_t TBufferMergerFile::Write(const char *name, Int_t opt, Int_t bufsize) +Int_t TBufferMergerFile::Write(const char *name, Int_t opt, Long64_t bufsize) { // Make sure the compression of the basket is done in the unlocked thread and // not in the locked section. diff --git a/io/io/src/TDirectoryFile.cxx b/io/io/src/TDirectoryFile.cxx index 3e9c01eaf9218..17c4982cd606a 100644 --- a/io/io/src/TDirectoryFile.cxx +++ b/io/io/src/TDirectoryFile.cxx @@ -406,7 +406,7 @@ TObject *TDirectoryFile::CloneObject(const TObject *obj, Bool_t autoadd /* = kTR // during the streaming .... TFile *filsav = gFile; gFile = nullptr; - const Int_t bufsize = 10000; + const Long64_t bufsize = 10000; TBufferFile buffer(TBuffer::kWrite,bufsize); buffer.MapObject(obj); //register obj in map to handle self reference { @@ -1665,8 +1665,10 @@ void TDirectoryFile::SaveSelf(Bool_t force) /// /// See also TDirectoryFile::GetBufferSize -void TDirectoryFile::SetBufferSize(Int_t bufsize) +void TDirectoryFile::SetBufferSize(Long64_t bufsize) { + if (bufsize > kMaxInt) + Fatal("SetBufferSize", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); fBufferSize = bufsize; } @@ -1853,7 +1855,7 @@ void TDirectoryFile::Streamer(TBuffer &b) /// For allowed options see TObject::Write(). /// The directory header info is rewritten on the directory header record. -Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize) +Int_t TDirectoryFile::Write(const char *, Int_t opt, Long64_t bufsize) { if (!IsWritable()) return 0; TDirectory::TContext ctxt(this); @@ -1874,7 +1876,7 @@ Int_t TDirectoryFile::Write(const char *, Int_t opt, Int_t bufsize) //////////////////////////////////////////////////////////////////////////////// /// One can not save a const TDirectory object. -Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const +Int_t TDirectoryFile::Write(const char *n, Int_t opt, Long64_t bufsize) const { Error("Write const","A const TDirectory object should not be saved. We try to proceed anyway."); return const_cast(this)->Write(n, opt, bufsize); @@ -1924,7 +1926,7 @@ Int_t TDirectoryFile::Write(const char *n, Int_t opt, Int_t bufsize) const /// WARNING: avoid special characters like '^','$','.' in the name as they /// are used by the regular expression parser (see TRegexp). -Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Int_t bufsize) +Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_t *option, Long64_t bufsize) { TDirectory::TContext ctxt(this); @@ -1951,7 +1953,11 @@ Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_ TKey *key=0, *oldkey=0; Int_t bsize = GetBufferSize(); - if (bufsize > 0) bsize = bufsize; + if (bufsize > 0) { + if (bufsize > kMaxInt) + Fatal("WriteTObject", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); + bsize = bufsize; + } const char *oname; if (name && *name) @@ -2039,7 +2045,7 @@ Int_t TDirectoryFile::WriteTObject(const TObject *obj, const char *name, Option_ /// ~~~ /// See also remarks in TDirectoryFile::WriteTObject -Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Int_t bufsize) +Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, const char *name, Option_t *option, Long64_t bufsize) { TClass *cl = TClass::GetClass(classname); if (!cl) { @@ -2066,7 +2072,7 @@ Int_t TDirectoryFile::WriteObjectAny(const void *obj, const char *classname, con /// An alternative is to call the function WriteObjectAny above. /// see TDirectoryFile::WriteTObject for comments -Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Int_t bufsize) +Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const char *name, Option_t *option, Long64_t bufsize) { TDirectory::TContext ctxt(this); @@ -2105,7 +2111,10 @@ Int_t TDirectoryFile::WriteObjectAny(const void *obj, const TClass *cl, const ch TKey *key, *oldkey = nullptr; Int_t bsize = GetBufferSize(); - if (bufsize > 0) bsize = bufsize; + if (bufsize > 0) { + Fatal("WriteObjectAny", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); + bsize = bufsize; + } TString opt = option; opt.ToLower(); diff --git a/io/io/src/TFile.cxx b/io/io/src/TFile.cxx index 44f2c8a912bdb..17d495bd6ac6b 100644 --- a/io/io/src/TFile.cxx +++ b/io/io/src/TFile.cxx @@ -1053,7 +1053,7 @@ void TFile::Close(Option_t *option) //////////////////////////////////////////////////////////////////////////////// /// Creates key for object and converts data to buffer. -TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Int_t bufsize) +TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, Long64_t bufsize) { return new TKey(obj, name, bufsize, mother); } @@ -1061,7 +1061,7 @@ TKey* TFile::CreateKey(TDirectory* mother, const TObject* obj, const char* name, //////////////////////////////////////////////////////////////////////////////// /// Creates key for object and converts data to buffer. -TKey* TFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Int_t bufsize) +TKey* TFile::CreateKey(TDirectory* mother, const void* obj, const TClass* cl, const char* name, Long64_t bufsize) { return new TKey(obj, cl, name, bufsize, mother); } @@ -2445,11 +2445,16 @@ void TFile::Streamer(TBuffer &b) //////////////////////////////////////////////////////////////////////////////// /// Increment statistics for buffer sizes of objects in this file. -void TFile::SumBuffer(Int_t bufsize) +void TFile::SumBuffer(Long64_t bufsize) { + if (bufsize > kMaxInt) + Fatal("SumBuffer", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); + else if (bufsize < 0) + Fatal("SumBuffer", "negative buffer size: 0x%llx.", bufsize); + fWritten++; - fSumBuffer += double(bufsize); - fSum2Buffer += double(bufsize) * double(bufsize); // avoid reaching MAXINT for temporary + fSumBuffer += bufsize; + fSum2Buffer += bufsize * bufsize; } //////////////////////////////////////////////////////////////////////////////// @@ -2464,7 +2469,7 @@ void TFile::SumBuffer(Int_t bufsize) /// The linked list of FREE segments is written. /// The file header is written (bytes 1->fBEGIN). -Int_t TFile::Write(const char *, Int_t opt, Int_t bufsize) +Int_t TFile::Write(const char *, Int_t opt, Long64_t bufsize) { if (!IsWritable()) { if (!TestBit(kWriteError)) { @@ -2494,7 +2499,7 @@ Int_t TFile::Write(const char *, Int_t opt, Int_t bufsize) //////////////////////////////////////////////////////////////////////////////// /// One can not save a const TDirectory object. -Int_t TFile::Write(const char *n, Int_t opt, Int_t bufsize) const +Int_t TFile::Write(const char *n, Int_t opt, Long64_t bufsize) const { Error("Write const","A const TFile object should not be saved. We try to proceed anyway."); return const_cast(this)->Write(n, opt, bufsize); @@ -4287,16 +4292,28 @@ Int_t TFile::GetReadaheadSize() } //______________________________________________________________________________ -void TFile::SetReadaheadSize(Int_t bytes) { fgReadaheadSize = bytes; } +void TFile::SetReadaheadSize(Long64_t bytes) { + assert (bytes <= kMaxInt); + fgReadaheadSize = bytes; +} //______________________________________________________________________________ -void TFile::SetFileBytesRead(Long64_t bytes) { fgBytesRead = bytes; } +void TFile::SetFileBytesRead(Long64_t bytes) { + assert (bytes <= kMaxInt); + fgBytesRead = bytes; +} //______________________________________________________________________________ -void TFile::SetFileBytesWritten(Long64_t bytes) { fgBytesWrite = bytes; } +void TFile::SetFileBytesWritten(Long64_t bytes) { + assert (bytes <= kMaxInt); + fgBytesWrite = bytes; +} //______________________________________________________________________________ -void TFile::SetFileReadCalls(Int_t readcalls) { fgReadCalls = readcalls; } +void TFile::SetFileReadCalls(Long64_t readcalls) { + assert (readcalls <= kMaxInt); + fgReadCalls = readcalls; +} //______________________________________________________________________________ Long64_t TFile::GetFileCounter() { return fgFileCounter; } @@ -4686,7 +4703,7 @@ void TFile::CpProgress(Long64_t bytesread, Long64_t size, TStopwatch &watch) /// Allows to copy this file to the dst URL. Returns kTRUE in case of success, /// kFALSE otherwise. -Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t bufsize) +Bool_t TFile::Cp(const char *dst, Bool_t progressbar, Long64_t bufsize) { Bool_t rmdestiferror = kFALSE; TStopwatch watch; @@ -4741,6 +4758,11 @@ Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t bufsize) sfile->Seek(0); dfile->Seek(0); + if (bufsize < 0) + Fatal("TFile::Cp", "Negative buffer size: 0x%llx.", bufsize); + else if (bufsize > kMaxUInt) { + Fatal("TFile::Cp", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxUInt); + } copybuffer = new char[bufsize]; if (!copybuffer) { ::Error("TFile::Cp", "cannot allocate the copy buffer"); @@ -4763,7 +4785,7 @@ Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t bufsize) Long64_t b1 = sfile->GetBytesRead() - b00; Long64_t readsize; - if (filesize - b1 > (Long64_t)bufsize) { + if (filesize - b1 > bufsize) { readsize = bufsize; } else { readsize = filesize - b1; @@ -4789,7 +4811,7 @@ Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t bufsize) goto copyout; } totalread += read; - } while (read == (Long64_t)bufsize); + } while (read == bufsize); if (progressbar) { CpProgress(totalread, filesize,watch); @@ -4818,7 +4840,7 @@ Bool_t TFile::Cp(const char *dst, Bool_t progressbar, UInt_t bufsize) /// kFALSE otherwise. Bool_t TFile::Cp(const char *src, const char *dst, Bool_t progressbar, - UInt_t bufsize) + Long64_t bufsize) { TUrl sURL(src, kTRUE); diff --git a/io/io/src/TFileCacheRead.cxx b/io/io/src/TFileCacheRead.cxx index 351adbf2b7958..8b50683fc5a4a 100644 --- a/io/io/src/TFileCacheRead.cxx +++ b/io/io/src/TFileCacheRead.cxx @@ -89,9 +89,14 @@ TFileCacheRead::TFileCacheRead() : TObject() //////////////////////////////////////////////////////////////////////////////// /// Creates a TFileCacheRead data structure. -TFileCacheRead::TFileCacheRead(TFile *file, Int_t bufsize, TObject *tree) +TFileCacheRead::TFileCacheRead(TFile *file, Long64_t bufsize, TObject *tree) : TObject() { + if (bufsize < 0) + Fatal("TFileCacheRead", "Negative buffer size: 0x%llx.", bufsize); + else if (bufsize > kMaxInt) { + Fatal("TFileCacheRead", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); + } if (bufsize <=10000) fBufferSize = 100000; else fBufferSize = bufsize; diff --git a/io/io/src/TFileCacheWrite.cxx b/io/io/src/TFileCacheWrite.cxx index 5aadb50ce8791..89c197ac0b1e8 100644 --- a/io/io/src/TFileCacheWrite.cxx +++ b/io/io/src/TFileCacheWrite.cxx @@ -49,9 +49,14 @@ TFileCacheWrite::TFileCacheWrite() : TObject() /// The size of the cache will be bufsize, /// if bufsize < 10000 a default size of 512 Kbytes is used -TFileCacheWrite::TFileCacheWrite(TFile *file, Int_t bufsize) +TFileCacheWrite::TFileCacheWrite(TFile *file, Long64_t bufsize) : TObject() { + if (bufsize < 0) + Fatal("TFileCacheWrite", "Negative buffer size: 0x%llx.", bufsize); + else if (bufsize > kMaxInt) { + Fatal("TFileCacheWrite", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); + } if (bufsize < 10000) bufsize = 512000; fBufferSize = bufsize; fSeekStart = 0; @@ -60,7 +65,7 @@ TFileCacheWrite::TFileCacheWrite(TFile *file, Int_t bufsize) fRecursive = kFALSE; fBuffer = new char[fBufferSize]; if (file) file->SetCacheWrite(this); - if (gDebug > 0) Info("TFileCacheWrite","Creating a write cache with buffersize=%d bytes",bufsize); + if (gDebug > 0) Info("TFileCacheWrite","Creating a write cache with buffersize=%lld bytes",bufsize); } //////////////////////////////////////////////////////////////////////////////// diff --git a/io/io/src/TKey.cxx b/io/io/src/TKey.cxx index 2567681d839bc..add90be50ce92 100644 --- a/io/io/src/TKey.cxx +++ b/io/io/src/TKey.cxx @@ -171,11 +171,16 @@ TKey::TKey(TDirectory* motherDir, const TKey &orig, UShort_t pidOffset) : TNamed /// Constructor called by TDirectoryFile::ReadKeys and by TFile::TFile. /// A TKey object is created to read the keys structure itself. -TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed() +TKey::TKey(Long64_t pointer, Long64_t nbytes, TDirectory* motherDir) : TNamed() { Build(motherDir, "", pointer); fSeekKey = pointer; + if (nbytes > kMaxInt) { + Fatal("TKey", "Integer overflow in byte size: 0x%llx for a max of 0x%x.", nbytes, kMaxInt); + } else if (nbytes < 0) { + Fatal("TKey", "Negative byte size: 0x%llx.", nbytes); + } fNbytes = nbytes; fBuffer = new char[nbytes]; keyAbsNumber++; SetUniqueID(keyAbsNumber); @@ -187,12 +192,17 @@ TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed() /// WARNING: in name avoid special characters like '^','$','.' that are used /// by the regular expression parser (see TRegexp). -TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, TDirectory* motherDir) +TKey::TKey(const char *name, const char *title, const TClass *cl, Long64_t nbytes, TDirectory* motherDir) : TNamed(name,title) { Build(motherDir, cl->GetName(), -1); fKeylen = Sizeof(); + if (nbytes > kMaxInt) { + Fatal("TKey", "Integer overflow in byte size: 0x%llx for a max of 0x%x.", nbytes, kMaxInt); + } else if (nbytes < 0) { + Fatal("TKey", "Negative byte size: 0x%llx.", nbytes); + } fObjlen = nbytes; Create(nbytes); } @@ -203,12 +213,17 @@ TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, /// WARNING: in name avoid special characters like '^','$','.' that are used /// by the regular expression parser (see TRegexp). -TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nbytes, TDirectory* motherDir) +TKey::TKey(const TString &name, const TString &title, const TClass *cl, Long64_t nbytes, TDirectory* motherDir) : TNamed(name,title) { Build(motherDir, cl->GetName(), -1); fKeylen = Sizeof(); + if (nbytes > kMaxInt) { + Fatal("TKey", "Integer overflow in byte size: 0x%llx for a max of 0x%x.", nbytes, kMaxInt); + } else if (nbytes < 0) { + Fatal("TKey", "Negative byte size: 0x%llx.", nbytes); + } fObjlen = nbytes; Create(nbytes); } @@ -219,7 +234,7 @@ TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nb /// WARNING: in name avoid special characters like '^','$','.' that are used /// by the regular expression parser (see TRegexp). -TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* motherDir) +TKey::TKey(const TObject *obj, const char *name, Long64_t bufsize, TDirectory* motherDir) : TNamed(name, obj->GetTitle()) { R__ASSERT(obj); @@ -294,7 +309,7 @@ TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* moth /// WARNING: in name avoid special characters like '^','$','.' that are used /// by the regular expression parser (see TRegexp). -TKey::TKey(const void *obj, const TClass *cl, const char *name, Int_t bufsize, TDirectory *motherDir) : TNamed(name, "") +TKey::TKey(const void *obj, const TClass *cl, const char *name, Long64_t bufsize, TDirectory *motherDir) : TNamed(name, "") { R__ASSERT(obj && cl); @@ -458,7 +473,7 @@ void TKey::Browse(TBrowser *b) /// If externFile!=0, key will be allocated in specified file, otherwise file /// of mother directory will be used. -void TKey::Create(Int_t nbytes, TFile* externFile) +void TKey::Create(Long64_t nbytes, TFile* externFile) { keyAbsNumber++; SetUniqueID(keyAbsNumber); @@ -468,7 +483,11 @@ void TKey::Create(Int_t nbytes, TFile* externFile) Error("Create","Cannot create key without file"); return; } - + if (nbytes > kMaxInt - fKeylen) { + Fatal("Create", "Integer overflow in byte size: 0x%llx for a max of 0x%x.", nbytes, kMaxInt); + } else if (nbytes < 0) { + Fatal("Create", "Negative byte size: 0x%llx.", nbytes); + } Int_t nsize = nbytes + fKeylen; TList *lfree = f->GetListOfFree(); TFree *f1 = (TFree*)lfree->First(); diff --git a/io/io/src/TMapFile.cxx b/io/io/src/TMapFile.cxx index 7692d5886a223..b0e610554df71 100644 --- a/io/io/src/TMapFile.cxx +++ b/io/io/src/TMapFile.cxx @@ -1124,7 +1124,7 @@ void TMapFile::ls(Option_t *) const //////////////////////////////////////////////////////////////////////////////// /// Increment statistics for buffer sizes of objects in this file. -void TMapFile::SumBuffer(Int_t bufsize) +void TMapFile::SumBuffer(Long64_t bufsize) { fWritten++; fSumBuffer += bufsize; diff --git a/io/sql/inc/TSQLFile.h b/io/sql/inc/TSQLFile.h index 6212462db8621..6c43069189b1d 100644 --- a/io/sql/inc/TSQLFile.h +++ b/io/sql/inc/TSQLFile.h @@ -205,8 +205,8 @@ class TSQLFile final : public TFile { void StopLogFile(); // *MENU* void Close(Option_t *option = "") final; // *MENU* - TKey *CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t bufsize) final; - TKey *CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Int_t bufsize) final; + TKey *CreateKey(TDirectory *mother, const TObject *obj, const char *name, Long64_t bufsize) final; + TKey *CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Long64_t bufsize) final; void DrawMap(const char * = "*", Option_t * = "") final {} void FillBuffer(char *&) final {} void Flush() final {} @@ -245,8 +245,8 @@ class TSQLFile final : public TFile { Int_t Sizeof() const final { return 0; } Bool_t WriteBuffer(const char *, Int_t) final { return kFALSE; } - Int_t Write(const char * = nullptr, Int_t = 0, Int_t = 0) final { return 0; } - Int_t Write(const char * = nullptr, Int_t = 0, Int_t = 0) const final { return 0; } + Int_t Write(const char * = nullptr, Int_t = 0, Long64_t = 0) final { return 0; } + Int_t Write(const char * = nullptr, Int_t = 0, Long64_t = 0) const final { return 0; } void WriteFree() final {} void WriteHeader() final; void WriteStreamerInfo() final; diff --git a/io/sql/src/TSQLFile.cxx b/io/sql/src/TSQLFile.cxx index 5d4db4cfd34d9..52b5ea857c281 100644 --- a/io/sql/src/TSQLFile.cxx +++ b/io/sql/src/TSQLFile.cxx @@ -762,7 +762,7 @@ Int_t TSQLFile::ReOpen(Option_t *mode) //////////////////////////////////////////////////////////////////////////////// /// create SQL key, which will store object in data base -TKey *TSQLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t) +TKey *TSQLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *name, Long64_t) { return new TKeySQL(mother, obj, name); } @@ -770,7 +770,7 @@ TKey *TSQLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *na //////////////////////////////////////////////////////////////////////////////// /// create SQL key, which will store object in data base -TKey *TSQLFile::CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Int_t) +TKey *TSQLFile::CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Long64_t) { return new TKeySQL(mother, obj, cl, name); } diff --git a/io/xml/inc/TXMLFile.h b/io/xml/inc/TXMLFile.h index 12cbc41de4571..346b5833517e8 100644 --- a/io/xml/inc/TXMLFile.h +++ b/io/xml/inc/TXMLFile.h @@ -53,8 +53,8 @@ class TXMLFile final : public TFile, public TXMLSetup { ~TXMLFile() override; void Close(Option_t *option = "") final; // *MENU* - TKey *CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t bufsize) final; - TKey *CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Int_t bufsize) final; + TKey *CreateKey(TDirectory *mother, const TObject *obj, const char *name, Long64_t bufsize) final; + TKey *CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Long64_t bufsize) final; void DrawMap(const char * = "*", Option_t * = "") final {} void FillBuffer(char *&) final {} void Flush() final {} @@ -91,8 +91,8 @@ class TXMLFile final : public TFile, public TXMLSetup { Int_t Sizeof() const final { return 0; } Bool_t WriteBuffer(const char *, Int_t) final { return kFALSE; } - Int_t Write(const char * = nullptr, Int_t = 0, Int_t = 0) final { return 0; } - Int_t Write(const char * = nullptr, Int_t = 0, Int_t = 0) const final { return 0; } + Int_t Write(const char * = nullptr, Int_t = 0, Long64_t = 0) final { return 0; } + Int_t Write(const char * = nullptr, Int_t = 0, Long64_t = 0) const final { return 0; } void WriteFree() final {} void WriteHeader() final {} void WriteStreamerInfo() final; diff --git a/io/xml/src/TXMLFile.cxx b/io/xml/src/TXMLFile.cxx index 6c022942fe08b..6be31bd47f13b 100644 --- a/io/xml/src/TXMLFile.cxx +++ b/io/xml/src/TXMLFile.cxx @@ -404,7 +404,7 @@ Int_t TXMLFile::ReOpen(Option_t *mode) //////////////////////////////////////////////////////////////////////////////// /// create XML key, which will store object in xml structures -TKey *TXMLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *name, Int_t) +TKey *TXMLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *name, Long64_t) { return new TKeyXML(mother, ++fKeyCounter, obj, name); } @@ -412,7 +412,7 @@ TKey *TXMLFile::CreateKey(TDirectory *mother, const TObject *obj, const char *na //////////////////////////////////////////////////////////////////////////////// /// create XML key, which will store object in xml structures -TKey *TXMLFile::CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Int_t) +TKey *TXMLFile::CreateKey(TDirectory *mother, const void *obj, const TClass *cl, const char *name, Long64_t) { return new TKeyXML(mother, ++fKeyCounter, obj, cl, name); } diff --git a/main/src/h2root.cxx b/main/src/h2root.cxx index 1e72e0cee44bd..f1eb7c2ba2919 100644 --- a/main/src/h2root.cxx +++ b/main/src/h2root.cxx @@ -269,7 +269,7 @@ extern void convert_cwn(Int_t id); extern void convert_rwn(Int_t id); Int_t golower = 1; -Int_t bufsize = 64000; +Long64_t bufsize = 64000; Int_t optcwn = 1; int main(int argc, char **argv) { @@ -297,7 +297,7 @@ int main(int argc, char **argv) optcwn = atoi(argv[7]); } if (argc > 6) { - bufsize = atoi(argv[6]); + bufsize = atol(argv[6]); } if (argc > 5) { record_size = atoi(argv[5]); diff --git a/net/net/inc/TMessage.h b/net/net/inc/TMessage.h index 90f4f377d1577..f8b964d925df3 100644 --- a/net/net/inc/TMessage.h +++ b/net/net/inc/TMessage.h @@ -62,11 +62,11 @@ friend class TXSocket; enum EStatusBits { kIsOwnerComp = BIT(19) // if TMessage owns fBufComp }; - TMessage(void *buf, Int_t bufsize, Bool_t adopt = kTRUE); // only called by T(P)Socket::Recv() + TMessage(void *buf, Long64_t bufsize, Bool_t adopt = kTRUE); // only called by T(P)Socket::Recv() void SetLength() const; // only called by T(P)Socket::Send() public: - TMessage(UInt_t what = kMESS_ANY, Int_t bufsize = TBuffer::kInitialSize); + TMessage(UInt_t what = kMESS_ANY, Long64_t bufsize = TBuffer::kInitialSize); virtual ~TMessage(); void ForceWriteInfo(TVirtualStreamerInfo *info, Bool_t force) override; diff --git a/net/net/inc/TParallelMergingFile.h b/net/net/inc/TParallelMergingFile.h index d956d1e871473..d1e34b9d0e465 100644 --- a/net/net/inc/TParallelMergingFile.h +++ b/net/net/inc/TParallelMergingFile.h @@ -53,8 +53,8 @@ class TParallelMergingFile : public TMemFile void Close(Option_t *option="") override; Bool_t OpenConnection(); Bool_t UploadAndReset(); - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) override; - Int_t Write(const char *name=nullptr, Int_t opt=0, Int_t bufsize=0) const override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t opt=0, Long64_t bufsize=0) const override; void WriteStreamerInfo() override; Int_t GetServerIdx() const { return fServerIdx; } diff --git a/net/net/src/TMessage.cxx b/net/net/src/TMessage.cxx index de34e427a5a3d..d2a2a0c6c3833 100644 --- a/net/net/src/TMessage.cxx +++ b/net/net/src/TMessage.cxx @@ -42,7 +42,7 @@ Bool_t TMessage::fgEvolution = kFALSE; /// the message will be compressed in TSocket using the zip algorithm /// (only if message is > 256 bytes). -TMessage::TMessage(UInt_t what, Int_t bufsize) : +TMessage::TMessage(UInt_t what, Long64_t bufsize) : TBufferFile(TBuffer::kWrite, bufsize + 2*sizeof(UInt_t)), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal) { @@ -67,7 +67,7 @@ TMessage::TMessage(UInt_t what, Int_t bufsize) : /// Create a TMessage object for reading objects. The objects will be /// read from buf. Use the What() method to get the message type. -TMessage::TMessage(void *buf, Int_t bufsize, Bool_t adopt) : TBufferFile(TBuffer::kRead, bufsize, buf, adopt), +TMessage::TMessage(void *buf, Long64_t bufsize, Bool_t adopt) : TBufferFile(TBuffer::kRead, bufsize, buf, adopt), fCompress(ROOT::RCompressionSetting::EAlgorithm::kUseGlobal) { // skip space at the beginning of the message reserved for the message length diff --git a/net/net/src/TParallelMergingFile.cxx b/net/net/src/TParallelMergingFile.cxx index b33baadd9310a..25084e988e39f 100644 --- a/net/net/src/TParallelMergingFile.cxx +++ b/net/net/src/TParallelMergingFile.cxx @@ -177,7 +177,7 @@ Bool_t TParallelMergingFile::UploadAndReset() /// The linked list of FREE segments is written. /// The file header is written (bytes 1->fBEGIN). -Int_t TParallelMergingFile::Write(const char *, Int_t opt, Int_t bufsize) +Int_t TParallelMergingFile::Write(const char *, Int_t opt, Long64_t bufsize) { std::size_t prevSize = GetBytesWritten(); auto nbytes = TMemFile::Write(0,opt,bufsize); @@ -193,7 +193,7 @@ Int_t TParallelMergingFile::Write(const char *, Int_t opt, Int_t bufsize) //////////////////////////////////////////////////////////////////////////////// /// One can not save a const TDirectory object. -Int_t TParallelMergingFile::Write(const char *n, Int_t opt, Int_t bufsize) const +Int_t TParallelMergingFile::Write(const char *n, Int_t opt, Long64_t bufsize) const { Error("Write const","A const TFile object should not be saved. We try to proceed anyway."); return const_cast(this)->Write(n, opt, bufsize); diff --git a/roottest/root/meta/MemberComments.ref b/roottest/root/meta/MemberComments.ref index ac6b3bc4e4872..f4461b1e69630 100644 --- a/roottest/root/meta/MemberComments.ref +++ b/roottest/root/meta/MemberComments.ref @@ -537,9 +537,9 @@ OBJ: TList TList Doubly linked list : 0 OBJ: TMethod Warning : 0 void TObject::Warning(const char* method, const char* msgfmt,...) const OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) const + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const OBJ: TMethod ls : 0 void TLine::ls(Option_t* option = "") const OBJ: TMethod ls : 0 diff --git a/roottest/root/meta/MemberComments_win32.ref b/roottest/root/meta/MemberComments_win32.ref index 67d1da4cedd81..ee99d1f414715 100644 --- a/roottest/root/meta/MemberComments_win32.ref +++ b/roottest/root/meta/MemberComments_win32.ref @@ -537,9 +537,9 @@ OBJ: TList TList Doubly linked list : 0 OBJ: TMethod Warning : 0 void TObject::Warning(const char* method, const char* msgfmt,...) const OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) const + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const OBJ: TMethod ls : 0 void TLine::ls(Option_t* option = "") const OBJ: TMethod ls : 0 diff --git a/roottest/root/meta/MemberComments_win64.ref b/roottest/root/meta/MemberComments_win64.ref index 67d1da4cedd81..ee99d1f414715 100644 --- a/roottest/root/meta/MemberComments_win64.ref +++ b/roottest/root/meta/MemberComments_win64.ref @@ -537,9 +537,9 @@ OBJ: TList TList Doubly linked list : 0 OBJ: TMethod Warning : 0 void TObject::Warning(const char* method, const char* msgfmt,...) const OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) OBJ: TMethod Write : 0 - Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Int_t bufsize = 0) const + Int_t TObject::Write(const char* name = nullptr, Int_t option = 0, Long64_t bufsize = 0) const OBJ: TMethod ls : 0 void TLine::ls(Option_t* option = "") const OBJ: TMethod ls : 0 diff --git a/tree/dataframe/src/RDFSnapshotHelpers.cxx b/tree/dataframe/src/RDFSnapshotHelpers.cxx index ce5c339a0511e..1b258383f41c1 100644 --- a/tree/dataframe/src/RDFSnapshotHelpers.cxx +++ b/tree/dataframe/src/RDFSnapshotHelpers.cxx @@ -196,7 +196,7 @@ void CreateFundamentalTypeBranch(TTree &outputTree, RBranchData &bd, void *value { // Logic taken from // TTree::BranchImpRef( - // const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel) + // const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, Long64_t bufsize, Int_t splitlevel) auto rootTypeChar = ROOT::Internal::RDF::TypeID2ROOTTypeName(*bd.fInputTypeID); if (rootTypeChar == ' ') { Warning("Snapshot", diff --git a/tree/ntuple/src/RFieldMeta.cxx b/tree/ntuple/src/RFieldMeta.cxx index 9ef7fa5e6a2fb..c2aaf52e0a3ad 100644 --- a/tree/ntuple/src/RFieldMeta.cxx +++ b/tree/ntuple/src/RFieldMeta.cxx @@ -1048,7 +1048,7 @@ class TBufferRecStreamer : public TBufferFile { RCallbackStreamerInfo fCallbackStreamerInfo; public: - TBufferRecStreamer(TBuffer::EMode mode, Int_t bufsize, RCallbackStreamerInfo callbackStreamerInfo) + TBufferRecStreamer(TBuffer::EMode mode, Long64_t bufsize, RCallbackStreamerInfo callbackStreamerInfo) : TBufferFile(mode, bufsize), fCallbackStreamerInfo(callbackStreamerInfo) { } diff --git a/tree/tree/inc/TBranch.h b/tree/tree/inc/TBranch.h index e88a6cf596e1a..06321de127aff 100644 --- a/tree/tree/inc/TBranch.h +++ b/tree/tree/inc/TBranch.h @@ -192,8 +192,8 @@ class TBranch : public TNamed, public TAttFill { public: TBranch(); - TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Int_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Long64_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Long64_t basketsize=32000, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); ~TBranch() override; virtual void AddBasket(TBasket &b, bool ondisk, Long64_t startEntry); @@ -271,7 +271,7 @@ class TBranch : public TNamed, public TAttFill { virtual void SetAddress(void *add); virtual void SetObject(void *objadd); virtual void SetAutoDelete(bool autodel=true); - virtual void SetBasketSize(Int_t bufsize); + virtual void SetBasketSize(Long64_t bufsize); virtual void SetBufferAddress(TBuffer *entryBuffer); void SetCompressionAlgorithm(Int_t algorithm = ROOT::RCompressionSetting::EAlgorithm::kUseGlobal); void SetCompressionLevel(Int_t level = ROOT::RCompressionSetting::ELevel::kUseMin); diff --git a/tree/tree/inc/TBranchClones.h b/tree/tree/inc/TBranchClones.h index 6154609a91906..4f57f1587aa27 100644 --- a/tree/tree/inc/TBranchClones.h +++ b/tree/tree/inc/TBranchClones.h @@ -38,13 +38,13 @@ class TBranchClones : public TBranch { friend class TTreeCloner; - void Init(TTree *tree, TBranch *parent, const char *name, void *clonesaddress, Int_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); + void Init(TTree *tree, TBranch *parent, const char *name, void *clonesaddress, Long64_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); Int_t FillImpl(ROOT::Internal::TBranchIMTHelper *) override; public: TBranchClones(); - TBranchClones(TTree *tree, const char *name, void *clonesaddress, Int_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); - TBranchClones(TBranch *parent, const char *name, void *clonesaddress, Int_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); + TBranchClones(TTree *tree, const char *name, void *clonesaddress, Long64_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); + TBranchClones(TBranch *parent, const char *name, void *clonesaddress, Long64_t basketsize=32000,Int_t compress=-1, Int_t splitlevel=1); ~TBranchClones() override; void Browse(TBrowser *b) override; @@ -57,7 +57,7 @@ class TBranchClones : public TBranch { void Reset(Option_t *option="") override; void ResetAfterMerge(TFileMergeInfo *) override; void SetAddress(void *add) override; - void SetBasketSize(Int_t bufsize) override; + void SetBasketSize(Long64_t bufsize) override; void SetTree(TTree *tree) override { fTree = tree; fBranchCount->SetTree(tree); } void UpdateFile() override; diff --git a/tree/tree/inc/TBranchElement.h b/tree/tree/inc/TBranchElement.h index 39c762041c414..4a451cc32bf53 100644 --- a/tree/tree/inc/TBranchElement.h +++ b/tree/tree/inc/TBranchElement.h @@ -122,12 +122,12 @@ class TBranchElement : public TBranch { void SetupInfo(); void SetBranchCount(TBranchElement* bre); void SetBranchCount2(TBranchElement* bre) { fBranchCount2 = bre; } - Int_t Unroll(const char* name, TClass* cltop, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype); + Int_t Unroll(const char* name, TClass* cltop, TClass* cl, char* ptr, Long64_t basketsize, Int_t splitlevel, Int_t btype); inline void ValidateAddress() const; - void Init(TTree *tree, TBranch *parent, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); - void Init(TTree *tree, TBranch *parent, const char* name, TClonesArray* clones, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - void Init(TTree *tree, TBranch *parent, const char* name, TVirtualCollectionProxy* cont, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + void Init(TTree *tree, TBranch *parent, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); + void Init(TTree *tree, TBranch *parent, const char* name, TClonesArray* clones, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + void Init(TTree *tree, TBranch *parent, const char* name, TVirtualCollectionProxy* cont, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); void SetActionSequence(TClass *originalClass, TStreamerInfo *localInfo, TStreamerInfoActions::TActionSequence::SequenceGetter_t create, TStreamerInfoActions::TActionSequence *&actionSequence); void ReadLeavesImpl(TBuffer& b); @@ -166,12 +166,12 @@ class TBranchElement : public TBranch { // Public Interface. public: TBranchElement(); - TBranchElement(TTree *tree, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); - TBranchElement(TTree *tree, const char* name, TClonesArray* clones, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - TBranchElement(TTree *tree, const char* name, TVirtualCollectionProxy* cont, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - TBranchElement(TBranch *parent, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); - TBranchElement(TBranch *parent, const char* name, TClonesArray* clones, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); - TBranchElement(TBranch *parent, const char* name, TVirtualCollectionProxy* cont, Int_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranchElement(TTree *tree, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); + TBranchElement(TTree *tree, const char* name, TClonesArray* clones, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranchElement(TTree *tree, const char* name, TVirtualCollectionProxy* cont, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranchElement(TBranch *parent, const char* name, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t btype = 0); + TBranchElement(TBranch *parent, const char* name, TClonesArray* clones, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); + TBranchElement(TBranch *parent, const char* name, TVirtualCollectionProxy* cont, Long64_t basketsize = 32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit); ~TBranchElement() override; @@ -222,7 +222,7 @@ class TBranchElement : public TBranch { void SetAddress(void* addobj) override; bool SetMakeClass(bool decomposeObj = true) override; void SetObject(void *objadd) override; - void SetBasketSize(Int_t bufsize) override; + void SetBasketSize(Long64_t bufsize) override; virtual void SetBranchFolder() { SetBit(kBranchFolder); } virtual void SetClassName(const char* name) { fClassName = name; } void SetOffset(Int_t offset) override; @@ -233,7 +233,7 @@ class TBranchElement : public TBranch { void SetupAddresses() override; virtual void SetType(Int_t btype) { fType = btype; } void UpdateFile() override; - void Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel); + void Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Long64_t bufsize, Int_t splitlevel); enum EBranchElementType { kLeafNode = 0, diff --git a/tree/tree/inc/TBranchObject.h b/tree/tree/inc/TBranchObject.h index 75dbbf96e5cf2..586b085490b23 100644 --- a/tree/tree/inc/TBranchObject.h +++ b/tree/tree/inc/TBranchObject.h @@ -42,12 +42,12 @@ class TBranchObject : public TBranch { TString fClassName; ///< Class name of referenced object TObject *fOldObject; ///< !Pointer to old object - void Init(TTree *tree, TBranch *parent, const char *name, const char *classname, void *addobj, Int_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr); + void Init(TTree *tree, TBranch *parent, const char *name, const char *classname, void *addobj, Long64_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr); public: TBranchObject(); - TBranchObject(TBranch *parent, const char *name, const char *classname, void *addobj, Int_t basketsize=32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit, bool isptrptr = true); - TBranchObject(TTree *tree, const char *name, const char *classname, void *addobj, Int_t basketsize=32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit, bool isptrptr = true); + TBranchObject(TBranch *parent, const char *name, const char *classname, void *addobj, Long64_t basketsize=32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit, bool isptrptr = true); + TBranchObject(TTree *tree, const char *name, const char *classname, void *addobj, Long64_t basketsize=32000, Int_t splitlevel = 0, Int_t compress = ROOT::RCompressionSetting::EAlgorithm::kInherit, bool isptrptr = true); ~TBranchObject() override; void Browse(TBrowser *b) override; @@ -61,7 +61,7 @@ class TBranchObject : public TBranch { void ResetAfterMerge(TFileMergeInfo *) override; void SetAddress(void *addobj) override; void SetAutoDelete(bool autodel=true) override; - void SetBasketSize(Int_t bufsize) override; + void SetBasketSize(Long64_t bufsize) override; void SetupAddresses() override; void UpdateAddress() override; diff --git a/tree/tree/inc/TBranchSTL.h b/tree/tree/inc/TBranchSTL.h index 9afff67341619..0ec1442edd6bc 100644 --- a/tree/tree/inc/TBranchSTL.h +++ b/tree/tree/inc/TBranchSTL.h @@ -24,10 +24,10 @@ class TBranchSTL: public TBranch { TBranchSTL(); TBranchSTL( TTree* tree, const char* name, TVirtualCollectionProxy* collProxy, - Int_t bufsize, Int_t splitlevel ); + Long64_t bufsize, Int_t splitlevel ); TBranchSTL( TBranch* parent, const char* name, TVirtualCollectionProxy* collProxy, - Int_t bufsize, Int_t splitlevel, + Long64_t bufsize, Int_t splitlevel, TStreamerInfo* info, Int_t id ); ~TBranchSTL() override; void Browse( TBrowser *b ) override; diff --git a/tree/tree/inc/TBufferSQL.h b/tree/tree/inc/TBufferSQL.h index eff029fa978b8..7813147842999 100644 --- a/tree/tree/inc/TBufferSQL.h +++ b/tree/tree/inc/TBufferSQL.h @@ -43,8 +43,8 @@ class TBufferSQL final : public TBufferFile { public: TBufferSQL(); TBufferSQL(TBuffer::EMode mode, std::vector *vc, TString *insert_query, TSQLRow **rowPtr); - TBufferSQL(TBuffer::EMode mode, Int_t bufsiz, std::vector *vc, TString *insert_query, TSQLRow **rowPtr); - TBufferSQL(TBuffer::EMode mode, Int_t bufsiz, std::vector *vc, TString *insert_query, TSQLRow **rowPtr,void *buf, bool adopt = true); + TBufferSQL(TBuffer::EMode mode, Long64_t bufsiz, std::vector *vc, TString *insert_query, TSQLRow **rowPtr); + TBufferSQL(TBuffer::EMode mode, Long64_t bufsiz, std::vector *vc, TString *insert_query, TSQLRow **rowPtr,void *buf, bool adopt = true); ~TBufferSQL() override; void ResetOffset(); diff --git a/tree/tree/inc/TChain.h b/tree/tree/inc/TChain.h index 8d362124ec261..24c20e8713858 100644 --- a/tree/tree/inc/TChain.h +++ b/tree/tree/inc/TChain.h @@ -132,7 +132,7 @@ class TChain : public TTree { virtual Long64_t Merge(const char *name, Option_t *option = ""); Long64_t Merge(TCollection *list, Option_t *option = "") override; Long64_t Merge(TCollection *list, TFileMergeInfo *info) override; - virtual Long64_t Merge(TFile *file, Int_t basketsize, Option_t *option=""); + virtual Long64_t Merge(TFile *file, Long64_t basketsize, Option_t *option=""); void Print(Option_t *option="") const override; Long64_t Process(const char *filename, Option_t *option="", Long64_t nentries=kMaxEntries, Long64_t firstentry=0) override; // *MENU* Long64_t Process(TSelector* selector, Option_t* option = "", Long64_t nentries = kMaxEntries, Long64_t firstentry = 0) override; diff --git a/tree/tree/inc/TNtuple.h b/tree/tree/inc/TNtuple.h index 3794097b6bb04..527eb4af63ffb 100644 --- a/tree/tree/inc/TNtuple.h +++ b/tree/tree/inc/TNtuple.h @@ -39,7 +39,7 @@ class TNtuple : public TTree { public: TNtuple(); - TNtuple(const char *name,const char *title, const char *varlist, Int_t bufsize=32000); + TNtuple(const char *name,const char *title, const char *varlist, Long64_t bufsize=32000); ~TNtuple() override; void Browse(TBrowser *b) override; diff --git a/tree/tree/inc/TNtupleD.h b/tree/tree/inc/TNtupleD.h index 63aded6eae49e..cac5381597e05 100644 --- a/tree/tree/inc/TNtupleD.h +++ b/tree/tree/inc/TNtupleD.h @@ -39,7 +39,7 @@ class TNtupleD : public TTree { public: TNtupleD(); - TNtupleD(const char *name,const char *title, const char *varlist, Int_t bufsize=32000); + TNtupleD(const char *name,const char *title, const char *varlist, Long64_t bufsize=32000); ~TNtupleD() override; void Browse(TBrowser *b) override; diff --git a/tree/tree/inc/TTree.h b/tree/tree/inc/TTree.h index 7609529df00fe..69cfe992749eb 100644 --- a/tree/tree/inc/TTree.h +++ b/tree/tree/inc/TTree.h @@ -81,8 +81,8 @@ namespace ROOT::Internal::TreeUtils { void TBranch__SetTree(TTree *tree, TObjArray &branches); TBranch *CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, EDataType datatype, void *addobj, - Int_t bufsize = 32000, Int_t splitlevel = 99); -TBranch *CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, void *addobj, Int_t bufsize = 32000, + Long64_t bufsize = 32000, Int_t splitlevel = 99); +TBranch *CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, void *addobj, Long64_t bufsize = 32000, Int_t splitlevel = 99); } @@ -187,19 +187,19 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker protected: friend TBranch *ROOT::Internal::TreeUtils::CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, - EDataType datatype, void *addobj, Int_t bufsize, + EDataType datatype, void *addobj, Long64_t bufsize, Int_t splitlevel); friend TBranch *ROOT::Internal::TreeUtils::CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, - void *addobj, Int_t bufsize, Int_t splitlevel); + void *addobj, Long64_t bufsize, Int_t splitlevel); virtual void KeepCircular(); - virtual TBranch *BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel); - virtual TBranch *BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel); - virtual TBranch *BranchImpRef(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel); - virtual TBranch *BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel); - virtual TBranch *BranchImpArr(const char* branchname, EDataType datatype, std::size_t N, void* addobj, Int_t bufsize, Int_t splitlevel); + virtual TBranch *BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Long64_t bufsize, Int_t splitlevel); + virtual TBranch *BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Long64_t bufsize, Int_t splitlevel); + virtual TBranch *BranchImpRef(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Long64_t bufsize, Int_t splitlevel); + virtual TBranch *BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Long64_t bufsize, Int_t splitlevel); + virtual TBranch *BranchImpArr(const char* branchname, EDataType datatype, std::size_t N, void* addobj, Long64_t bufsize, Int_t splitlevel); virtual Int_t CheckBranchAddressType(TBranch* branch, TClass* ptrClass, EDataType datatype, bool ptr); - virtual TBranch *BronchExec(const char* name, const char* classname, void* addobj, bool isptrptr, Int_t bufsize, Int_t splitlevel); - friend TBranch *TTreeBranchImpRef(TTree *tree, const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel); + virtual TBranch *BronchExec(const char* name, const char* classname, void* addobj, bool isptrptr, Long64_t bufsize, Int_t splitlevel); + friend TBranch *TTreeBranchImpRef(TTree *tree, const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Long64_t bufsize, Int_t splitlevel); Int_t SetBranchAddressImp(TBranch *branch, void* addr, TBranch** ptr); virtual TLeaf *GetLeafImpl(const char* branchname, const char* leafname); @@ -386,7 +386,7 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker /// A small value for bufsize is beneficial if entries in the Tree are accessed randomly and the Tree is in split mode. /// \param[in] splitlevel If T is a class or struct and splitlevel > 0, the members of the object are serialised as separate branches. /// \return Pointer to the TBranch that was created. The branch is owned by the tree. - template TBranch *Branch(const char* name, T* obj, Int_t bufsize = 32000, Int_t splitlevel = 99) + template TBranch *Branch(const char* name, T* obj, Long64_t bufsize = 32000, Int_t splitlevel = 99) { return BranchImpRef(name, TClass::GetClass(), TDataType::GetType(typeid(T)), obj, bufsize, splitlevel); } @@ -403,42 +403,42 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker /// A small value for bufsize is beneficial if entries in the Tree are accessed randomly and the Tree is in split mode. /// \param[in] splitlevel If T is a class or struct and splitlevel > 0, the members of the object are serialised as separate branches. /// \return Pointer to the TBranch that was created. The branch is owned by the tree. - template TBranch *Branch(const char* name, T** addobj, Int_t bufsize = 32000, Int_t splitlevel = 99) + template TBranch *Branch(const char* name, T** addobj, Long64_t bufsize = 32000, Int_t splitlevel = 99) { return BranchImp(name, TClass::GetClass(), addobj, bufsize, splitlevel); } - virtual Int_t Branch(TCollection* list, Int_t bufsize = 32000, Int_t splitlevel = 99, const char* name = ""); - virtual Int_t Branch(TList* list, Int_t bufsize = 32000, Int_t splitlevel = 99); - virtual Int_t Branch(const char* folder, Int_t bufsize = 32000, Int_t splitlevel = 99); - virtual TBranch *Branch(const char* name, void* address, const char* leaflist, Int_t bufsize = 32000); - TBranch *Branch(const char* name, char* address, const char* leaflist, Int_t bufsize = 32000) + virtual Int_t Branch(TCollection* list, Long64_t bufsize = 32000, Int_t splitlevel = 99, const char* name = ""); + virtual Int_t Branch(TList* list, Long64_t bufsize = 32000, Int_t splitlevel = 99); + virtual Int_t Branch(const char* folder, Long64_t bufsize = 32000, Int_t splitlevel = 99); + virtual TBranch *Branch(const char* name, void* address, const char* leaflist, Long64_t bufsize = 32000); + TBranch *Branch(const char* name, char* address, const char* leaflist, Long64_t bufsize = 32000) { // Overload to avoid confusion between this signature and the template instance. return Branch(name,(void*)address,leaflist,bufsize); } - TBranch *Branch(const char* name, Longptr_t address, const char* leaflist, Int_t bufsize = 32000) + TBranch *Branch(const char* name, Longptr_t address, const char* leaflist, Long64_t bufsize = 32000) { // Overload to avoid confusion between this signature and the template instance. return Branch(name,(void*)address,leaflist,bufsize); } - TBranch *Branch(const char* name, int address, const char* leaflist, Int_t bufsize = 32000) + TBranch *Branch(const char* name, int address, const char* leaflist, Long64_t bufsize = 32000) { // Overload to avoid confusion between this signature and the template instance. return Branch(name,(void*)(Longptr_t)address,leaflist,bufsize); } - virtual TBranch *Branch(const char* name, const char* classname, void* addobj, Int_t bufsize = 32000, Int_t splitlevel = 99); - template TBranch *Branch(const char* name, const char* classname, T* obj, Int_t bufsize = 32000, Int_t splitlevel = 99) + virtual TBranch *Branch(const char* name, const char* classname, void* addobj, Long64_t bufsize = 32000, Int_t splitlevel = 99); + template TBranch *Branch(const char* name, const char* classname, T* obj, Long64_t bufsize = 32000, Int_t splitlevel = 99) { // See BranchImpRed for details. Here we __ignore return BranchImpRef(name, classname, TClass::GetClass(), obj, bufsize, splitlevel); } - template TBranch *Branch(const char* name, const char* classname, T** addobj, Int_t bufsize = 32000, Int_t splitlevel = 99) + template TBranch *Branch(const char* name, const char* classname, T** addobj, Long64_t bufsize = 32000, Int_t splitlevel = 99) { // See BranchImp for details return BranchImp(name, classname, TClass::GetClass(), addobj, bufsize, splitlevel); } - template TBranch *Branch(const char* name, std::array *obj, Int_t bufsize = 32000, Int_t splitlevel = 99) + template TBranch *Branch(const char* name, std::array *obj, Long64_t bufsize = 32000, Int_t splitlevel = 99) { TClass *cl = TClass::GetClass(); if (cl) { @@ -449,8 +449,8 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker } return BranchImpArr(name, TDataType::GetType(typeid(T)), N, obj, bufsize, splitlevel); } - virtual TBranch *Bronch(const char* name, const char* classname, void* addobj, Int_t bufsize = 32000, Int_t splitlevel = 99); - virtual TBranch *BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize = 32000, Int_t splitlevel = 1); + virtual TBranch *Bronch(const char* name, const char* classname, void* addobj, Long64_t bufsize = 32000, Int_t splitlevel = 99); + virtual TBranch *BranchOld(const char* name, const char* classname, void* addobj, Long64_t bufsize = 32000, Int_t splitlevel = 1); virtual TBranch *BranchRef(); void Browse(TBrowser*) override; virtual Int_t BuildIndex(const char *majorname, const char *minorname = "0", bool long64major = false, bool long64minor = false); @@ -660,7 +660,7 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker virtual bool SetAlias(const char* aliasName, const char* aliasFormula); virtual void SetAutoSave(Long64_t autos = -300000000); virtual void SetAutoFlush(Long64_t autof = -30000000); - virtual void SetBasketSize(const char* bname, Int_t buffsize = 16000); + virtual void SetBasketSize(const char* bname, Long64_t bufsize = 16000); virtual Int_t SetBranchAddress(const char *bname,void *add, TBranch **ptr = nullptr); virtual Int_t SetBranchAddress(const char *bname,void *add, TClass *realClass, EDataType datatype, bool isptr); virtual Int_t SetBranchAddress(const char *bname,void *add, TBranch **ptr, TClass *realClass, EDataType datatype, bool isptr); @@ -743,8 +743,8 @@ class TTree : public TNamed, public TAttLine, public TAttFill, public TAttMarker virtual Int_t StopCacheLearningPhase(); virtual Int_t UnbinnedFit(const char* funcname, const char* varexp, const char* selection = "", Option_t* option = "", Long64_t nentries = kMaxEntries, Long64_t firstentry = 0); void UseCurrentStyle() override; - Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) override; - Int_t Write(const char *name=nullptr, Int_t option=0, Int_t bufsize=0) const override; + Int_t Write(const char *name=nullptr, Int_t option=0, Long64_t bufsize=0) override; + Int_t Write(const char *name=nullptr, Int_t option=0, Long64_t bufsize=0) const override; ClassDefOverride(TTree, 20) // Tree descriptor (the main ROOT I/O class) }; diff --git a/tree/tree/inc/TTreeCache.h b/tree/tree/inc/TTreeCache.h index 9b8621c3d7be7..dce5fddc0a125 100644 --- a/tree/tree/inc/TTreeCache.h +++ b/tree/tree/inc/TTreeCache.h @@ -127,7 +127,7 @@ class TTreeCache : public TFileCacheRead { public: TTreeCache(); - TTreeCache(TTree *tree, Int_t bufsize=0); + TTreeCache(TTree *tree, Long64_t bufsize=0); ~TTreeCache() override; Int_t AddBranch(TBranch *b, bool subgbranches = false) override; Int_t AddBranch(const char *branch, bool subbranches = false) override; @@ -162,7 +162,7 @@ class TTreeCache : public TFileCacheRead { virtual void ResetCache(); void ResetMissCache(); // Reset the miss cache. void SetAutoCreated(bool val) {fAutoCreated = val;} - Int_t SetBufferSize(Long64_t buffersize) override; + Int_t SetBufferSize(Long64_t bufsize) override; virtual void SetEntryRange(Long64_t emin, Long64_t emax); void SetFile(TFile *file, TFile::ECacheAction action=TFile::kDisconnect) override; virtual void SetLearnPrefill(EPrefillType type = kNoPrefill); diff --git a/tree/tree/inc/TTreeCacheUnzip.h b/tree/tree/inc/TTreeCacheUnzip.h index 28177e2ca61fb..71553d86be09d 100644 --- a/tree/tree/inc/TTreeCacheUnzip.h +++ b/tree/tree/inc/TTreeCacheUnzip.h @@ -117,7 +117,7 @@ class TTreeCacheUnzip : public TTreeCache { public: TTreeCacheUnzip(); - TTreeCacheUnzip(TTree *tree, Int_t buffersize=0); + TTreeCacheUnzip(TTree *tree, Long64_t buffersize=0); ~TTreeCacheUnzip() override; Int_t AddBranch(TBranch *b, bool subbranches = false) override; diff --git a/tree/tree/inc/TTreeSQL.h b/tree/tree/inc/TTreeSQL.h index 5fedf6d5d64bb..b51051b1bf63b 100644 --- a/tree/tree/inc/TTreeSQL.h +++ b/tree/tree/inc/TTreeSQL.h @@ -65,21 +65,21 @@ class TTreeSQL : public TTree { bool CreateTable(const TString& table); TBasket *CreateBasket(TBranch * br) override; - TBranch *BranchImp(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel) override; - TBranch *BranchImp(const char *branchname, TClass *ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel) override; + TBranch *BranchImp(const char *branchname, const char *classname, TClass *ptrClass, void *addobj, Long64_t bufsize, Int_t splitlevel) override; + TBranch *BranchImp(const char *branchname, TClass *ptrClass, void *addobj, Long64_t bufsize, Int_t splitlevel) override; public: TTreeSQL(TSQLServer * server, TString DB, const TString& table); ~TTreeSQL() override; - Int_t Branch(TCollection *list, Int_t bufsize=32000, Int_t splitlevel=99, const char *name="") override; - Int_t Branch(TList *list, Int_t bufsize=32000, Int_t splitlevel=99) override; - Int_t Branch(const char *folder, Int_t bufsize=32000, Int_t splitlevel=99) override; - TBranch *Bronch(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99) override; - TBranch *BranchOld(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=1) override; - TBranch *Branch(const char *name, const char *classname, void *addobj, Int_t bufsize=32000, Int_t splitlevel=99) override; + Int_t Branch(TCollection *list, Long64_t bufsize=32000, Int_t splitlevel=99, const char *name="") override; + Int_t Branch(TList *list, Long64_t bufsize=32000, Int_t splitlevel=99) override; + Int_t Branch(const char *folder, Long64_t bufsize=32000, Int_t splitlevel=99) override; + TBranch *Bronch(const char *name, const char *classname, void *addobj, Long64_t bufsize=32000, Int_t splitlevel=99) override; + TBranch *BranchOld(const char *name, const char *classname, void *addobj, Long64_t bufsize=32000, Int_t splitlevel=1) override; + TBranch *Branch(const char *name, const char *classname, void *addobj, Long64_t bufsize=32000, Int_t splitlevel=99) override; - TBranch *Branch(const char *name, void *address, const char *leaflist, Int_t bufsize) override; + TBranch *Branch(const char *name, void *address, const char *leaflist, Long64_t bufsize) override; Int_t Fill() override; Int_t GetEntry(Long64_t entry=0, Int_t getall=0) override; diff --git a/tree/tree/src/TBranch.cxx b/tree/tree/src/TBranch.cxx index a44cf713d1916..6b9d1102625a9 100644 --- a/tree/tree/src/TBranch.cxx +++ b/tree/tree/src/TBranch.cxx @@ -195,7 +195,7 @@ TBranch::TBranch() /// /// Note that this function is invoked by TTree::Branch -TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Int_t basketsize, Int_t compress) +TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leaflist, Long64_t basketsize, Int_t compress) : TNamed(name, leaflist) , TAttFill(0, 1001) , fCompress(compress) @@ -239,6 +239,8 @@ TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leafl , fReadLeaves(&TBranch::ReadLeavesImpl) , fFillLeaves(&TBranch::FillLeavesImpl) { + if (basketsize > kMaxInt) + Fatal("TBranch", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); Init(name,leaflist,compress); } @@ -248,7 +250,7 @@ TBranch::TBranch(TTree *tree, const char *name, void *address, const char *leafl /// See documentation for /// TBranch::TBranch(TTree *, const char *, void *, const char *, Int_t, Int_t) -TBranch::TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Int_t basketsize, +TBranch::TBranch(TBranch *parent, const char *name, void *address, const char *leaflist, Long64_t basketsize, Int_t compress) : TNamed(name, leaflist) , TAttFill(0, 1001) @@ -293,6 +295,8 @@ TBranch::TBranch(TBranch *parent, const char *name, void *address, const char *l , fReadLeaves(&TBranch::ReadLeavesImpl) , fFillLeaves(&TBranch::FillLeavesImpl) { + if (basketsize > kMaxInt) + Fatal("TBranch", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); Init(name,leaflist,compress); } @@ -2738,8 +2742,10 @@ void TBranch::SetAutoDelete(bool autodel) /// Set the basket size /// The function makes sure that the basket size is greater than fEntryOffsetlen -void TBranch::SetBasketSize(Int_t bufsize) +void TBranch::SetBasketSize(Long64_t bufsize) { + if (bufsize > kMaxInt) + Fatal("SetBasketSize", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); Int_t minsize = 100 + fName.Length(); if (bufsize < minsize+fEntryOffsetLen) bufsize = minsize+fEntryOffsetLen; fBasketSize = bufsize; diff --git a/tree/tree/src/TBranchClones.cxx b/tree/tree/src/TBranchClones.cxx index 13c51dbc03278..7909c8cfd75ce 100644 --- a/tree/tree/src/TBranchClones.cxx +++ b/tree/tree/src/TBranchClones.cxx @@ -49,7 +49,7 @@ TBranchClones::TBranchClones() //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TBranchClones::TBranchClones(TTree *tree, const char* name, void* pointer, Int_t basketsize, Int_t compress, Int_t splitlevel) +TBranchClones::TBranchClones(TTree *tree, const char* name, void* pointer, Long64_t basketsize, Int_t compress, Int_t splitlevel) : TBranch() , fList(nullptr) , fRead(0) @@ -63,7 +63,7 @@ TBranchClones::TBranchClones(TTree *tree, const char* name, void* pointer, Int_t //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TBranchClones::TBranchClones(TBranch *parent, const char* name, void* pointer, Int_t basketsize, Int_t compress, Int_t splitlevel) +TBranchClones::TBranchClones(TBranch *parent, const char* name, void* pointer, Long64_t basketsize, Int_t compress, Int_t splitlevel) : TBranch() , fList(nullptr) , fRead(0) @@ -77,7 +77,7 @@ TBranchClones::TBranchClones(TBranch *parent, const char* name, void* pointer, I //////////////////////////////////////////////////////////////////////////////// /// Initialization (non-virtual, to be called from constructor). -void TBranchClones::Init(TTree *tree, TBranch *parent, const char* name, void* pointer, Int_t basketsize, Int_t compress, Int_t splitlevel) +void TBranchClones::Init(TTree *tree, TBranch *parent, const char* name, void* pointer, Long64_t basketsize, Int_t compress, Int_t splitlevel) { if (tree==nullptr && parent!=nullptr) tree = parent->GetTree(); fTree = tree; @@ -110,6 +110,8 @@ void TBranchClones::Init(TTree *tree, TBranch *parent, const char* name, void* p fSplitLevel = splitlevel; // Create a branch to store the array count. + if (basketsize > kMaxInt) + Fatal("Init", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); if (basketsize < 100) { basketsize = 100; } @@ -369,7 +371,7 @@ void TBranchClones::SetAddress(void* addr) //////////////////////////////////////////////////////////////////////////////// /// Reset basket size for all sub-branches. -void TBranchClones::SetBasketSize(Int_t bufsize) +void TBranchClones::SetBasketSize(Long64_t bufsize) { TBranch::SetBasketSize(bufsize); diff --git a/tree/tree/src/TBranchElement.cxx b/tree/tree/src/TBranchElement.cxx index a8227be2e1bac..175035d6ef8e9 100644 --- a/tree/tree/src/TBranchElement.cxx +++ b/tree/tree/src/TBranchElement.cxx @@ -209,7 +209,7 @@ TBranchElement::TBranchElement() /// /// If splitlevel > 0 this branch in turn is split into sub-branches. -TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype) +TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize, Int_t splitlevel, Int_t btype) : TBranch() , fClassName(sinfo->GetName()) , fParentName() @@ -256,7 +256,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TStreamerInfo* si /// /// If splitlevel > 0 this branch in turn is split into sub-branches. -TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype) +TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize, Int_t splitlevel, Int_t btype) : TBranch() , fClassName(sinfo->GetName()) , fParentName() @@ -301,7 +301,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TStreamerInfo /// /// If splitlevel > 0 this branch in turn is split into sub-branches. -void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Int_t basketsize, Int_t splitlevel, Int_t btype) +void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStreamerInfo* sinfo, Int_t id, char* pointer, Long64_t basketsize, Int_t splitlevel, Int_t btype) { TString name(bname); @@ -367,7 +367,8 @@ void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStrea // Make sure the basket is big enough to contain the // entry offset array plus 100 bytes of data. // - + if (basketsize > kMaxInt) + Fatal("Init", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); if (basketsize < (100 + fEntryOffsetLen)) { basketsize = 100 + fEntryOffsetLen; } @@ -693,7 +694,7 @@ void TBranchElement::Init(TTree *tree, TBranch *parent,const char* bname, TStrea /// /// If splitlevel > 0 this branch in turn is split into sub branches. -TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress) +TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clones, Long64_t basketsize, Int_t splitlevel, Int_t compress) : TBranch() , fClassName("TClonesArray") , fParentName() @@ -720,7 +721,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TClonesArray* clo /// /// If splitlevel > 0 this branch in turn is split into sub branches. -TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress) +TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* clones, Long64_t basketsize, Int_t splitlevel, Int_t compress) : TBranch() , fClassName("TClonesArray") , fParentName() @@ -747,7 +748,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TClonesArray* /// /// If splitlevel > 0 this branch in turn is split into sub branches. -void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TClonesArray* clones, Int_t basketsize, Int_t splitlevel, Int_t compress) +void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TClonesArray* clones, Long64_t basketsize, Int_t splitlevel, Int_t compress) { fCollProxy = nullptr; fSplitLevel = splitlevel; @@ -848,7 +849,7 @@ void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TClon /// /// If splitlevel > 0 this branch in turn is split into sub branches. -TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress) +TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectionProxy* cont, Long64_t basketsize, Int_t splitlevel, Int_t compress) : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() @@ -874,7 +875,7 @@ TBranchElement::TBranchElement(TTree *tree, const char* bname, TVirtualCollectio /// /// If splitlevel > 0 this branch in turn is split into sub branches. -TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress) +TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Long64_t basketsize, Int_t splitlevel, Int_t compress) : TBranch() , fClassName(cont->GetCollectionClass()->GetName()) , fParentName() @@ -900,7 +901,7 @@ TBranchElement::TBranchElement(TBranch *parent, const char* bname, TVirtualColle /// /// If splitlevel > 0 this branch in turn is split into sub branches. -void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Int_t basketsize, Int_t splitlevel, Int_t compress) +void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TVirtualCollectionProxy* cont, Long64_t basketsize, Int_t splitlevel, Int_t compress) { fCollProxy = cont->Generate(); TString name( bname ); @@ -945,7 +946,8 @@ void TBranchElement::Init(TTree *tree, TBranch *parent, const char* bname, TVirt fCompress = bfile->GetCompressionSettings(); } } - + if (basketsize > kMaxInt) + Fatal("Init", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); if (basketsize < 100) { basketsize = 100; } @@ -5574,7 +5576,7 @@ void TBranchElement::SetAddressImpl(void* addr, bool implied, Int_t offset) //////////////////////////////////////////////////////////////////////////////// /// Reset the basket size for all sub-branches of this branch element. -void TBranchElement::SetBasketSize(Int_t bufsize) +void TBranchElement::SetBasketSize(Long64_t bufsize) { TBranch::SetBasketSize(bufsize); Int_t nbranches = fBranches.GetEntriesFast(); @@ -6136,7 +6138,7 @@ void TBranchElement::Streamer(TBuffer& R__b) /// This version of Unroll was formerly embedded in TTree::BronchExec /// It is moved here so we can make sure to call SetReadActionSequence. -void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Int_t bufsize, Int_t splitlevel) +void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, char* objptr, Long64_t bufsize, Int_t splitlevel) { // // Do we have a final dot in our name? @@ -6270,7 +6272,7 @@ void TBranchElement::Unroll(const char *name, TClass *cl, TStreamerInfo *sinfo, /// except for a TObject base class of a class which has the /// can ignore tobject streamer flag set. -Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Int_t basketsize, Int_t splitlevel, Int_t btype) +Int_t TBranchElement::Unroll(const char* name, TClass* clParent, TClass* cl, char* ptr, Long64_t basketsize, Int_t splitlevel, Int_t btype) { //---------------------------------------------------------------------------- // Handling the case of STL collections of pointers diff --git a/tree/tree/src/TBranchObject.cxx b/tree/tree/src/TBranchObject.cxx index 7f77edee333ee..5f955502ed22c 100644 --- a/tree/tree/src/TBranchObject.cxx +++ b/tree/tree/src/TBranchObject.cxx @@ -46,7 +46,7 @@ TBranchObject::TBranchObject() //////////////////////////////////////////////////////////////////////////////// /// Create a BranchObject. -TBranchObject::TBranchObject(TTree *tree, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr /* = true */) +TBranchObject::TBranchObject(TTree *tree, const char* name, const char* classname, void* addobj, Long64_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr /* = true */) : TBranch() { Init(tree,nullptr,name,classname,addobj,basketsize,splitlevel,compress,isptrptr); @@ -55,7 +55,7 @@ TBranchObject::TBranchObject(TTree *tree, const char* name, const char* classnam //////////////////////////////////////////////////////////////////////////////// /// Create a BranchObject. -TBranchObject::TBranchObject(TBranch *parent, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr /* = true */) +TBranchObject::TBranchObject(TBranch *parent, const char* name, const char* classname, void* addobj, Long64_t basketsize, Int_t splitlevel, Int_t compress, bool isptrptr /* = true */) : TBranch() { Init(nullptr,parent,name,classname,addobj,basketsize,splitlevel,compress,isptrptr); @@ -64,7 +64,7 @@ TBranchObject::TBranchObject(TBranch *parent, const char* name, const char* clas //////////////////////////////////////////////////////////////////////////////// /// Initialization routine (run from the constructor so do not make this function virtual) -void TBranchObject::Init(TTree *tree, TBranch *parent, const char* name, const char* classname, void* addobj, Int_t basketsize, Int_t /*splitlevel*/, Int_t compress, bool isptrptr) +void TBranchObject::Init(TTree *tree, TBranch *parent, const char* name, const char* classname, void* addobj, Long64_t basketsize, Int_t /*splitlevel*/, Int_t compress, bool isptrptr) { if (tree==nullptr && parent!=nullptr) tree = parent->GetTree(); fTree = tree; @@ -113,6 +113,8 @@ void TBranchObject::Init(TTree *tree, TBranch *parent, const char* name, const c if (basketsize < 100) { basketsize = 100; } + if (basketsize > kMaxInt) + Fatal("Init", "Integer overflow in basket size: 0x%llx for a max of 0x%x.", basketsize, kMaxInt); fBasketSize = basketsize; fAddress = (char*) addobj; fClassName = classname; @@ -527,7 +529,7 @@ void TBranchObject::SetAutoDelete(bool autodel) //////////////////////////////////////////////////////////////////////////////// /// Reset basket size for all subbranches of this branch. -void TBranchObject::SetBasketSize(Int_t bufsize) +void TBranchObject::SetBasketSize(Long64_t bufsize) { TBranch::SetBasketSize(bufsize); diff --git a/tree/tree/src/TBranchSTL.cxx b/tree/tree/src/TBranchSTL.cxx index 7e69b3ba0422b..3703d5d9df421 100644 --- a/tree/tree/src/TBranchSTL.cxx +++ b/tree/tree/src/TBranchSTL.cxx @@ -46,10 +46,12 @@ TBranchSTL::TBranchSTL(): TBranchSTL::TBranchSTL(TTree *tree, const char *name, TVirtualCollectionProxy *collProxy, - Int_t bufsize, Int_t splitlevel ) + Long64_t bufsize, Int_t splitlevel ) { fTree = tree; fCollProxy = collProxy; + if (bufsize > kMaxInt) + Fatal("TBranchSTL", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); fBasketSize = bufsize; fSplitLevel = splitlevel; fContName = collProxy->GetCollectionClass()->GetName(); @@ -88,11 +90,13 @@ TBranchSTL::TBranchSTL(TTree *tree, const char *name, TBranchSTL::TBranchSTL(TBranch* parent, const char* name, TVirtualCollectionProxy* collProxy, - Int_t bufsize, Int_t splitlevel, + Long64_t bufsize, Int_t splitlevel, TStreamerInfo* info, Int_t id ) { fTree = parent->GetTree(); fCollProxy = collProxy; + if (bufsize > kMaxInt) + Fatal("TBranchSTL", "Integer overflow in buffer size: 0x%llx for a max of 0x%x.", bufsize, kMaxInt); fBasketSize = bufsize; fSplitLevel = splitlevel; fContName = collProxy->GetCollectionClass()->GetName(); diff --git a/tree/tree/src/TBufferSQL.cxx b/tree/tree/src/TBufferSQL.cxx index 2e93a05253040..ba4d09306ef5c 100644 --- a/tree/tree/src/TBufferSQL.cxx +++ b/tree/tree/src/TBufferSQL.cxx @@ -41,7 +41,7 @@ TBufferSQL::TBufferSQL(TBuffer::EMode mode, std::vector *vc, //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TBufferSQL::TBufferSQL(TBuffer::EMode mode, Int_t bufsize, std::vector *vc, +TBufferSQL::TBufferSQL(TBuffer::EMode mode, Long64_t bufsize, std::vector *vc, TString *insert_query, TSQLRow ** r) : TBufferFile(mode,bufsize), fColumnVec(vc), fInsertQuery(insert_query), fRowPtr(r) @@ -52,7 +52,7 @@ TBufferSQL::TBufferSQL(TBuffer::EMode mode, Int_t bufsize, std::vector *v //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TBufferSQL::TBufferSQL(TBuffer::EMode mode, Int_t bufsize, std::vector *vc, +TBufferSQL::TBufferSQL(TBuffer::EMode mode, Long64_t bufsize, std::vector *vc, TString *insert_query, TSQLRow ** r, void *buf, bool adopt) : TBufferFile(mode,bufsize,buf,adopt), diff --git a/tree/tree/src/TChain.cxx b/tree/tree/src/TChain.cxx index b9079f6c92c54..94b988e35364f 100644 --- a/tree/tree/src/TChain.cxx +++ b/tree/tree/src/TChain.cxx @@ -2016,7 +2016,7 @@ Long64_t TChain::Merge(TCollection* /* list */, TFileMergeInfo *) /// } /// ~~~ -Long64_t TChain::Merge(TFile* file, Int_t basketsize, Option_t* option) +Long64_t TChain::Merge(TFile* file, Long64_t basketsize, Option_t* option) { // We must have been passed a file, we will use it // later to reset the compression level of the branches. diff --git a/tree/tree/src/TNtuple.cxx b/tree/tree/src/TNtuple.cxx index 69dbc12efd682..2ff552bbcd8ba 100644 --- a/tree/tree/src/TNtuple.cxx +++ b/tree/tree/src/TNtuple.cxx @@ -62,7 +62,7 @@ TNtuple::TNtuple(): TTree() /// - Use TTree to create branches with variables of different data types. /// - Use TTree when the number of branches is large (> 100). -TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Int_t bufsize) +TNtuple::TNtuple(const char *name, const char *title, const char *varlist, Long64_t bufsize) :TTree(name,title) { Int_t i; diff --git a/tree/tree/src/TNtupleD.cxx b/tree/tree/src/TNtupleD.cxx index 1aa334611895c..b4ec305581499 100644 --- a/tree/tree/src/TNtupleD.cxx +++ b/tree/tree/src/TNtupleD.cxx @@ -61,7 +61,7 @@ TNtupleD::TNtupleD(): TTree() /// - Use TTree to create branches with variables of different data types. /// - Use TTree when the number of branches is large (> 100). -TNtupleD::TNtupleD(const char *name, const char *title, const char *varlist, Int_t bufsize) +TNtupleD::TNtupleD(const char *name, const char *title, const char *varlist, Long64_t bufsize) :TTree(name,title) { Int_t i; diff --git a/tree/tree/src/TTree.cxx b/tree/tree/src/TTree.cxx index 26ab8bdb4f33d..0893cc95f2080 100644 --- a/tree/tree/src/TTree.cxx +++ b/tree/tree/src/TTree.cxx @@ -1579,7 +1579,7 @@ namespace { /// \see TTree::Branch() /// -TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel) +TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* ptrClass, void* addobj, Long64_t bufsize, Int_t splitlevel) { TClass* claim = TClass::GetClass(classname); if (!ptrClass) { @@ -1627,7 +1627,7 @@ TBranch* TTree::BranchImp(const char* branchname, const char* classname, TClass* /// Same as TTree::Branch but automatic detection of the class name. /// \see TTree::Branch -TBranch* TTree::BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Int_t bufsize, Int_t splitlevel) +TBranch* TTree::BranchImp(const char* branchname, TClass* ptrClass, void* addobj, Long64_t bufsize, Int_t splitlevel) { if (!ptrClass) { Error("Branch", "The pointer specified for %s is not of a class known to ROOT", branchname); @@ -1660,7 +1660,7 @@ TBranch* TTree::BranchImp(const char* branchname, TClass* ptrClass, void* addobj /// Same as TTree::Branch but automatic detection of the class name. /// \see TTree::Branch -TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Int_t bufsize, Int_t splitlevel) +TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TClass* ptrClass, void *addobj, Long64_t bufsize, Int_t splitlevel) { TClass* claim = TClass::GetClass(classname); if (!ptrClass) { @@ -1720,7 +1720,7 @@ TBranch* TTree::BranchImpRef(const char* branchname, const char *classname, TCla /// Same as TTree::Branch but automatic detection of the class name. /// \see TTree::Branch -TBranch* TTree::BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Int_t bufsize, Int_t splitlevel) +TBranch* TTree::BranchImpRef(const char* branchname, TClass* ptrClass, EDataType datatype, void* addobj, Long64_t bufsize, Int_t splitlevel) { if (!ptrClass) { if (datatype == kOther_t || datatype == kNoType_t) { @@ -1756,7 +1756,7 @@ TBranch* TTree::BranchImpRef(const char* branchname, TClass* ptrClass, EDataType //////////////////////////////////////////////////////////////////////////////// // Wrapper to turn Branch call with an std::array into the relevant leaf list // call -TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Int_t bufsize, +TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::size_t N, void *addobj, Long64_t bufsize, Int_t /* splitlevel */) { if (datatype == kOther_t || datatype == kNoType_t) { @@ -1774,7 +1774,7 @@ TBranch *TTree::BranchImpArr(const char *branchname, EDataType datatype, std::si //////////////////////////////////////////////////////////////////////////////// /// Deprecated function. Use next function instead. -Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */) +Int_t TTree::Branch(TList* li, Long64_t bufsize /* = 32000 */ , Int_t splitlevel /* = 99 */) { return Branch((TCollection*) li, bufsize, splitlevel); } @@ -1861,7 +1861,7 @@ Int_t TTree::Branch(TList* li, Int_t bufsize /* = 32000 */ , Int_t splitlevel /* /// } /// ~~~ -Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */) +Int_t TTree::Branch(TCollection* li, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */, const char* name /* = "" */) { if (!li) { @@ -1908,7 +1908,7 @@ Int_t TTree::Branch(TCollection* li, Int_t bufsize /* = 32000 */, Int_t splitlev /// Create one branch for each element in the folder. /// Returns the total number of branches created. -Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) +Int_t TTree::Branch(const char* foldername, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) { TObject* ob = gROOT->FindObjectAny(foldername); if (!ob) { @@ -2014,7 +2014,7 @@ Int_t TTree::Branch(const char* foldername, Int_t bufsize /* = 32000 */, Int_t s /// A small value for bufsize is optimum if you intend to access /// the entries in the Tree randomly and your Tree is in split mode. -TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Int_t bufsize /* = 32000 */) +TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, Long64_t bufsize /* = 32000 */) { TBranch* branch = new TBranch(this, name, address, leaflist, bufsize); if (branch->IsZombie()) { @@ -2049,7 +2049,7 @@ TBranch* TTree::Branch(const char* name, void* address, const char* leaflist, In /// Note: if the split level is set to the default (99), TTree::Branch will /// not issue a warning if the class can not be split. -TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) +TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) { if (fgBranchStyle == 1) { return Bronch(name, classname, addobj, bufsize, splitlevel); @@ -2102,7 +2102,7 @@ TBranch* TTree::Branch(const char* name, const char* classname, void* addobj, In /// A small value for bufsize is optimum if you intend to access /// the entries in the Tree randomly and your Tree is in split mode. -TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */) +TBranch* TTree::BranchOld(const char* name, const char* classname, void* addobj, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 1 */) { TClass* cl = TClass::GetClass(classname); if (!cl) { @@ -2432,7 +2432,7 @@ TBranch* TTree::BranchRef() /// Note: if the split level is set to the default (99), TTree::Branch will /// not issue a warning if the class can not be split. -TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) +TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) { return BronchExec(name, classname, addr, true, bufsize, splitlevel); } @@ -2440,7 +2440,7 @@ TBranch* TTree::Bronch(const char* name, const char* classname, void* addr, Int_ //////////////////////////////////////////////////////////////////////////////// /// Helper function implementing TTree::Bronch and TTree::Branch(const char *name, T &obj); -TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Int_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) +TBranch* TTree::BronchExec(const char* name, const char* classname, void* addr, bool isptrptr, Long64_t bufsize /* = 32000 */, Int_t splitlevel /* = 99 */) { TClass* cl = TClass::GetClass(classname); if (!cl) { @@ -8563,7 +8563,7 @@ void TTree::SetAutoSave(Long64_t autos) /// see TRegexp for wildcarding options /// bufsize = branch basket size -void TTree::SetBasketSize(const char* bname, Int_t bufsize) +void TTree::SetBasketSize(const char* bname, Long64_t bufsize) { Int_t nleaves = fLeaves.GetEntriesFast(); TRegexp re(bname, true); @@ -10007,7 +10007,7 @@ void TTree::UseCurrentStyle() /// Write this object to the current directory. For more see TObject::Write /// If option & kFlushBasket, call FlushBasket before writing the tree. -Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const +Int_t TTree::Write(const char *name, Int_t option, Long64_t bufsize) const { FlushBasketsImpl(); if (R__unlikely(option & kOnlyPrepStep)) @@ -10019,7 +10019,7 @@ Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) const /// Write this object to the current directory. For more see TObject::Write /// If option & kFlushBasket, call FlushBasket before writing the tree. -Int_t TTree::Write(const char *name, Int_t option, Int_t bufsize) +Int_t TTree::Write(const char *name, Int_t option, Long64_t bufsize) { return ((const TTree*)this)->Write(name, option, bufsize); } @@ -10126,13 +10126,13 @@ Option_t* TTreeFriendLeafIter::GetOption() const } TBranch *ROOT::Internal::TreeUtils::CallBranchImpRef(TTree &tree, const char *branchname, TClass *ptrClass, - EDataType datatype, void *addobj, Int_t bufsize, Int_t splitlevel) + EDataType datatype, void *addobj, Long64_t bufsize, Int_t splitlevel) { return tree.BranchImpRef(branchname, ptrClass, datatype, addobj, bufsize, splitlevel); } TBranch *ROOT::Internal::TreeUtils::CallBranchImp(TTree &tree, const char *branchname, TClass *ptrClass, void *addobj, - Int_t bufsize, Int_t splitlevel) + Long64_t bufsize, Int_t splitlevel) { return tree.BranchImp(branchname, ptrClass, addobj, bufsize, splitlevel); } diff --git a/tree/tree/src/TTreeCache.cxx b/tree/tree/src/TTreeCache.cxx index 285cbc6b47c3d..45720e634b115 100644 --- a/tree/tree/src/TTreeCache.cxx +++ b/tree/tree/src/TTreeCache.cxx @@ -316,7 +316,7 @@ TTreeCache::TTreeCache() : TFileCacheRead(), fPrefillType(GetConfiguredPrefillTy //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TTreeCache::TTreeCache(TTree *tree, Int_t bufsize) +TTreeCache::TTreeCache(TTree *tree, Long64_t bufsize) : TFileCacheRead(tree->GetCurrentFile(), bufsize, tree), fEntryMax(tree->GetEntriesFast()), fEntryNext(0), fBrNames(new TList), fTree(tree), fPrefillType(GetConfiguredPrefillType()) { @@ -2069,15 +2069,15 @@ void TTreeCache::ResetCache() /// - 1 if some or all of the buffer content has been made unavailable /// - -1 on error -Int_t TTreeCache::SetBufferSize(Long64_t buffersize) +Int_t TTreeCache::SetBufferSize(Long64_t bufsize) { Int_t prevsize = GetBufferSize(); - Int_t res = TFileCacheRead::SetBufferSize(buffersize); + Int_t res = TFileCacheRead::SetBufferSize(bufsize); if (res < 0) { return res; } - if (res == 0 && buffersize <= prevsize) { + if (res == 0 && bufsize <= prevsize) { return res; } diff --git a/tree/tree/src/TTreeCacheUnzip.cxx b/tree/tree/src/TTreeCacheUnzip.cxx index 507a23d0e218c..ced580eabd241 100644 --- a/tree/tree/src/TTreeCacheUnzip.cxx +++ b/tree/tree/src/TTreeCacheUnzip.cxx @@ -174,7 +174,7 @@ TTreeCacheUnzip::TTreeCacheUnzip() : TTreeCache(), //////////////////////////////////////////////////////////////////////////////// /// Constructor. -TTreeCacheUnzip::TTreeCacheUnzip(TTree *tree, Int_t bufsize) : TTreeCache(tree,bufsize), +TTreeCacheUnzip::TTreeCacheUnzip(TTree *tree, Long64_t bufsize) : TTreeCache(tree,bufsize), fAsyncReading(false), fEmpty(true), fCycle(0), @@ -356,9 +356,9 @@ bool TTreeCacheUnzip::FillBuffer() /// - 1 if some or all of the buffer content has been made unavailable /// - -1 on error -Int_t TTreeCacheUnzip::SetBufferSize(Long64_t buffersize) +Int_t TTreeCacheUnzip::SetBufferSize(Long64_t bufsize) { - Int_t res = TTreeCache::SetBufferSize(buffersize); + Int_t res = TTreeCache::SetBufferSize(bufsize); if (res < 0) { return res; } diff --git a/tree/tree/src/TTreeSQL.cxx b/tree/tree/src/TTreeSQL.cxx index 6e7106d35f96c..d47b36fb0bd5a 100644 --- a/tree/tree/src/TTreeSQL.cxx +++ b/tree/tree/src/TTreeSQL.cxx @@ -73,7 +73,7 @@ TTreeSQL::TTreeSQL(TSQLServer *server, TString DB, const TString& table) : /// Not implemented yet TBranch* TTreeSQL::BranchImp(const char *, const char *, - TClass *, void *, Int_t , + TClass *, void *, Long64_t , Int_t ) { Fatal("BranchImp","Not implemented yet"); @@ -84,7 +84,7 @@ TBranch* TTreeSQL::BranchImp(const char *, const char *, /// Not implemented yet TBranch* TTreeSQL::BranchImp(const char *, TClass *, - void *, Int_t , Int_t ) + void *, Long64_t , Int_t ) { Fatal("BranchImp","Not implemented yet"); return nullptr; @@ -92,7 +92,7 @@ TBranch* TTreeSQL::BranchImp(const char *, TClass *, //////////////////////////////////////////////////////////////////////////////// /// Not implemented yet -Int_t TTreeSQL::Branch(TCollection *, Int_t, +Int_t TTreeSQL::Branch(TCollection *, Long64_t, Int_t, const char *) { Fatal("Branch","Not implemented yet"); @@ -102,7 +102,7 @@ Int_t TTreeSQL::Branch(TCollection *, Int_t, //////////////////////////////////////////////////////////////////////////////// /// Not implemented yet -Int_t TTreeSQL::Branch(TList *, Int_t, Int_t) +Int_t TTreeSQL::Branch(TList *, Long64_t, Int_t) { Fatal("Branch","Not implemented yet"); return 0; @@ -111,7 +111,7 @@ Int_t TTreeSQL::Branch(TList *, Int_t, Int_t) //////////////////////////////////////////////////////////////////////////////// /// Not implemented yet -Int_t TTreeSQL::Branch(const char *, Int_t , +Int_t TTreeSQL::Branch(const char *, Long64_t , Int_t) { Fatal("Branch","Not implemented yet"); @@ -122,7 +122,7 @@ Int_t TTreeSQL::Branch(const char *, Int_t , /// Not implemented yet TBranch* TTreeSQL::Bronch(const char *, const char *, void *, - Int_t, Int_t) + Long64_t, Int_t) { Fatal("Bronch","Not implemented yet"); return nullptr; @@ -132,7 +132,7 @@ TBranch* TTreeSQL::Bronch(const char *, const char *, void *, /// Not implemented yet TBranch* TTreeSQL::BranchOld(const char *, const char *, - void *, Int_t, Int_t) + void *, Long64_t, Int_t) { Fatal("BranchOld","Not implemented yet"); return nullptr; @@ -142,7 +142,7 @@ TBranch* TTreeSQL::BranchOld(const char *, const char *, /// Not implemented yet TBranch *TTreeSQL::Branch(const char *, const char *, void *, - Int_t, Int_t) + Long64_t, Int_t) { Fatal("Branch","Not implemented yet"); return nullptr; @@ -152,7 +152,7 @@ TBranch *TTreeSQL::Branch(const char *, const char *, void *, /// Create a branch TBranch * TTreeSQL::Branch(const char *name, void *address, - const char *leaflist, Int_t bufsize) + const char *leaflist, Long64_t bufsize) { Int_t nb = fBranches.GetEntriesFast(); TBranch *branch; From 278a78c70960712e39ce2d6e45ec684b0a35d017 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sat, 29 Nov 2025 18:36:40 +0100 Subject: [PATCH 02/22] io: Add data structure for 64 bit byte count. In order to support 64 bits byte counts, which do not fit in the space reserved for them in the stream (4 bytes minus 2 control bits) and to work around the fact that the variables that holds the position and the byte count information in Streamer functions are only 32 bits (see arguments to TBufferFile::WriteVersion and TBufferFile::ReadVersion), we need to pass them indirectly when they needs 64 bits Since the streaming is inherently serial, we can leverage the sequence of calls and cache the 64 bits values in a queue. The bytecount that can not be stored in place inside the io stream will be held in a collection (fByteCounts) that need to be stored externally to the buffer. --- io/io/inc/TBufferFile.h | 13 +++++++++++++ io/io/src/TBufferFile.cxx | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 3d2e37141fcc4..209fb617348d2 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -52,6 +52,16 @@ class TBufferFile : public TBufferIO { TStreamerInfo *fInfo{nullptr}; ///< Pointer to TStreamerInfo object writing/reading the buffer InfoList_t fInfoStack; ///< Stack of pointers to the TStreamerInfos + using ByteCountLocator_t = std::size_t; // This might become a pair if we implement chunked keys + using ByteCountStack_t = std::vector; + ByteCountStack_t fByteCountStack; ///; + // fByteCounts will be stored either in the header/summary tkey or at the end + // of the last segment/chunk for a large TKey. + ByteCountFinder_t fByteCounts; ///< Map to find the byte count value for a given position + // Default ctor TBufferFile() {} // NOLINT: not allowed to use = default because of TObject::kIsOnHeap detection, see ROOT-10300 @@ -62,6 +72,7 @@ class TBufferFile : public TBufferIO { Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char* classname); void CheckCount(UInt_t offset) override; UInt_t CheckObject(UInt_t offset, const TClass *cl, Bool_t readClass = kFALSE); + UInt_t ReserveByteCount(); void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse) override; @@ -106,6 +117,8 @@ class TBufferFile : public TBufferIO { TObject *ReadObject(const TClass *cl) override; + ByteCountFinder_t GetByteCounts() const { return fByteCounts; } + using TBufferIO::CheckObject; // basic types and arrays of basic types diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index dd533c88a20ce..1a8948faff1fe 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -3327,6 +3327,22 @@ UInt_t TBufferFile::CheckObject(UInt_t offset, const TClass *cl, Bool_t readClas return offset; } +//////////////////////////////////////////////////////////////////////////////// +/// Reserve space for a leading byte count and return the position where to +/// store the byte count value. +/// +/// \param[in] mask The mask to apply to the placeholder value (default kByteCountMask) +/// \return The position (cntpos) where the byte count should be stored later, +/// or 0 if the position exceeds kMaxInt + +UInt_t TBufferFile::ReserveByteCount() +{ + // reserve space for leading byte count + auto full_cntpos = fBufCur - fBuffer; + fByteCountStack.push_back(full_cntpos); + *this << (UInt_t)kByteCountMask; // placeholder for byte count + return full_cntpos < kMaxInt ? full_cntpos : kMaxInt; +} //////////////////////////////////////////////////////////////////////////////// /// Read max bytes from the I/O buffer into buf. The function returns From 684d5a5c5f3258e84feb09336c1f4e2b191777e9 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sat, 29 Nov 2025 18:55:15 +0100 Subject: [PATCH 03/22] io: Support 64 bits position/byte-count in reading --- io/io/src/TBufferFile.cxx | 82 +++++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 8 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 1a8948faff1fe..dc3c596ebc148 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -360,10 +360,30 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char *classname) { - if (!bcnt) return 0; - R__ASSERT(startpos <= kMaxUInt && bcnt <= kMaxUInt); - Long64_t offset = 0; + R__ASSERT(!fByteCountStack.empty()); + if (startpos == kMaxInt) { + // The position is above 1GB and was cached using a 32 bit variable. + startpos = fByteCountStack.back(); + } + if (bcnt == kMaxInt) { + // in case we are checking a byte count for which we postponed + // the writing because it was too large, we retrieve it now + auto it = fByteCounts.find(startpos); + if (it != fByteCounts.end()) { + bcnt = it->second; + } else { + bcnt = 0; + Error("CheckByteCount", + "Could not find byte count for position %llu in the byte count map (size=%zu)", + startpos, fByteCounts.size()); + } + } + fByteCountStack.pop_back(); + + if (!bcnt) + return 0; + Long64_t offset = 0; Longptr_t endpos = Longptr_t(fBuffer) + startpos + bcnt + sizeof(UInt_t); if (Longptr_t(fBufCur) != endpos) { @@ -390,7 +410,7 @@ Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const T if ( ((char *)endpos) > fBufMax ) { offset = fBufMax-fBufCur; Error("CheckByteCount", - "Byte count probably corrupted around buffer position %llu:\n\t%llu for a possible maximum of %lld", + "Byte count probably corrupted around buffer position %llu:\n\tByte count is %llu while the buffer size is %lld", startpos, bcnt, offset); fBufCur = fBufMax; @@ -2749,6 +2769,8 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) bcnt = 0; } else { fVersion = 1; + if (objTag) + fByteCountStack.push_back(fBufCur - fBuffer); startpos = UInt_t(fBufCur-fBuffer); *this >> tag; } @@ -2932,7 +2954,10 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass if (startpos) { // before reading object save start position - *startpos = UInt_t(fBufCur-fBuffer); + auto full_startpos = fBufCur - fBuffer; + *startpos = full_startpos < kMaxInt ? UInt_t(full_startpos) : kMaxInt; + if (bcnt) + fByteCountStack.push_back(full_startpos); } // read byte count (older files don't have byte count) @@ -2956,9 +2981,30 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass fBufCur -= sizeof(UInt_t); v.cnt = 0; } - if (bcnt) *bcnt = (v.cnt & ~kByteCountMask); + if (bcnt) { + if (!v.cnt) { + // no byte count stored + *bcnt = 0; + if (startpos) // Undo the push_back only if it happened. + fByteCountStack.pop_back(); + } else { + *bcnt = (v.cnt & ~kByteCountMask); + if (*bcnt == 0) { + // The byte count was stored but is zero, this means the data + // did not fit and thus we stored it in 'fByteCounts' instead. + // Mark this case by setting startpos to kMaxInt. + *bcnt = kMaxInt; + if (startpos) + *startpos = kMaxInt; + } + } + } frombuf(this->fBufCur,&version); + // NOTE: The code above is not straightforward to refactor by a call + // to ReadVersionNoCheckSum because of the following code need the + // 'raw' value in `v`. + if (version<=1) { if (version <= 0) { if (cl) { @@ -3038,7 +3084,10 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) if (startpos) { // before reading object save start position - *startpos = UInt_t(fBufCur-fBuffer); + auto full_startpos = fBufCur - fBuffer; + *startpos = full_startpos < kMaxInt ? UInt_t(full_startpos) : kMaxInt; + if (bcnt) + fByteCountStack.push_back(full_startpos); } // read byte count (older files don't have byte count) @@ -3062,7 +3111,24 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) fBufCur -= sizeof(UInt_t); v.cnt = 0; } - if (bcnt) *bcnt = (v.cnt & ~kByteCountMask); + if (bcnt) { + if (!v.cnt) { + // no byte count stored + *bcnt = 0; + if (startpos) // Undo the push_back only if it happened. + fByteCountStack.pop_back(); + } else { + *bcnt = (v.cnt & ~kByteCountMask); + if (*bcnt == 0) { + // The byte count was stored but is zero, this means the data + // did not fit and thus we stored it in 'fByteCounts' instead. + // Mark this case by setting startpos to kMaxInt. + *bcnt = kMaxInt; + if (startpos) + *startpos = kMaxInt; + } + } + } frombuf(this->fBufCur,&version); return version; From 29e675df7a2cc753b2e89b90e273c85a3e4ee064 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sat, 29 Nov 2025 18:54:43 +0100 Subject: [PATCH 04/22] io: Support 64 bits position/byte-count in writing --- io/io/src/TBufferFile.cxx | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index dc3c596ebc148..fb33ab45c9a9a 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -323,7 +323,26 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) && (fBufCur >= fBuffer) && static_cast(fBufCur - fBuffer) <= std::numeric_limits::max() && "Byte count position is after the end of the buffer"); - const UInt_t cnt = UInt_t(fBufCur - fBuffer) - UInt_t(cntpos) - sizeof(UInt_t); + + // We can either make this unconditional or we could split the routine + // in two, one with a new signature and guarantee to get the 64bit position + // (which may be chunk number + local offset) and one with the old signature + // which uses the stack to get the position and call the new one. + // This (of course) also requires that we do the 'same' to the WriteVersion + // routines. + R__ASSERT( !fByteCountStack.empty() ); + if (cntpos == kMaxInt) { + cntpos = fByteCountStack.back(); + } + fByteCountStack.pop_back(); + // if we are not in the same TKey chunk or if the cntpos is too large to fit in UInt_t + // let's postpone the writing of the byte count + const ULong64_t full_cnt = ULong64_t(fBufCur - fBuffer) - cntpos - sizeof(UInt_t); + if (full_cnt >= kMaxMapCount) { + fByteCounts[cntpos] = full_cnt; + return; + } + UInt_t cnt = static_cast(full_cnt); char *buf = (char *)(fBuffer + cntpos); // if true, pack byte count in two consecutive shorts, so it can @@ -2714,8 +2733,7 @@ void TBufferFile::WriteObjectClass(const void *actualObjectStart, const TClass * } // reserve space for leading byte count - UInt_t cntpos = UInt_t(fBufCur-fBuffer); - fBufCur += sizeof(UInt_t); + UInt_t cntpos = ReserveByteCount(); // write class of object first Int_t mapsize = fMap->Capacity(); // The slot depends on the capacity and WriteClass might induce an increase. @@ -3214,8 +3232,7 @@ UInt_t TBufferFile::WriteVersion(const TClass *cl, Bool_t useBcnt) UInt_t cntpos = 0; if (useBcnt) { // reserve space for leading byte count - cntpos = UInt_t(fBufCur-fBuffer); - fBufCur += sizeof(UInt_t); + cntpos = ReserveByteCount(); } Version_t version = cl->GetClassVersion(); @@ -3244,8 +3261,7 @@ UInt_t TBufferFile::WriteVersionMemberWise(const TClass *cl, Bool_t useBcnt) UInt_t cntpos = 0; if (useBcnt) { // reserve space for leading byte count - cntpos = UInt_t(fBufCur-fBuffer); - fBufCur += sizeof(UInt_t); + cntpos = ReserveByteCount(); } Version_t version = cl->GetClassVersion(); From b4cc23d7ffbe6e990f2cb7f4f9a8be7e1923cb3c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sat, 29 Nov 2025 18:58:00 +0100 Subject: [PATCH 05/22] io/nfc: add comment --- tree/tree/src/TBranch.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tree/tree/src/TBranch.cxx b/tree/tree/src/TBranch.cxx index 6b9d1102625a9..768434017ea86 100644 --- a/tree/tree/src/TBranch.cxx +++ b/tree/tree/src/TBranch.cxx @@ -979,6 +979,7 @@ Int_t TBranch::FillEntryBuffer(TBasket* basket, TBuffer* buf, Int_t& lnew) fEntryBuffer->SetBufferOffset(objectStart); *fEntryBuffer >> tag; if (tag & kByteCountMask) { + // Ignore byte count. *fEntryBuffer >> tag; } if (tag == kNewClassTag) { @@ -1457,7 +1458,7 @@ bool TBranch::SupportsBulkRead() const { /// the number of elements corresponding to each entries. /// /// For each entry the number of elements is the multiplication of -/// +/// /// ~~~{.cpp} /// TLeaf *leaf = static_cast(branch->GetListOfLeaves()->At(0)); /// auto len = leaf->GetLen(); From ec9caac367c0ffcc5a6c375a1e5e61205af1f4d7 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 2 Dec 2025 11:09:44 -0600 Subject: [PATCH 06/22] io: Add Set/GetByteCounts to TBufferFile Note to store and restore the larger than 1GB byte count use: // Copy the content of the const reference. auto bytecounts{b.GetByteCounts()}; ... b.SetByteCounts(std::move(bytecounts)); --- io/io/inc/TBufferFile.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 209fb617348d2..19bd6808dc3a7 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -117,7 +117,8 @@ class TBufferFile : public TBufferIO { TObject *ReadObject(const TClass *cl) override; - ByteCountFinder_t GetByteCounts() const { return fByteCounts; } + const ByteCountFinder_t& GetByteCounts() const { return fByteCounts; } + void SetByteCounts(ByteCountFinder_t &&byteCounts) { fByteCounts = std::move(byteCounts); } using TBufferIO::CheckObject; From fcfd908e80ccbf3a0a062eff40e89a93f10420e2 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 8 Dec 2025 14:24:29 -0600 Subject: [PATCH 07/22] io: Add reset of new bytecount infrastructure --- io/io/inc/TBufferFile.h | 2 ++ io/io/src/TBufferFile.cxx | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 19bd6808dc3a7..ba6d0be4d881d 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -120,6 +120,8 @@ class TBufferFile : public TBufferIO { const ByteCountFinder_t& GetByteCounts() const { return fByteCounts; } void SetByteCounts(ByteCountFinder_t &&byteCounts) { fByteCounts = std::move(byteCounts); } + void ResetMap() override; + using TBufferIO::CheckObject; // basic types and arrays of basic types diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index fb33ab45c9a9a..fc28af2c82be7 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -114,6 +114,16 @@ TBufferFile::~TBufferFile() { } +//////////////////////////////////////////////////////////////////////////////// +/// Reset buffer maps and clear byte-count tracking structures. + +void TBufferFile::ResetMap() +{ + TBufferIO::ResetMap(); + fByteCountStack.clear(); + fByteCounts.clear(); +} + //////////////////////////////////////////////////////////////////////////////// /// Increment level. From 6dfcf4fe3a3cc8de55935946cd950a51480acf1a Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 8 Dec 2025 14:25:17 -0600 Subject: [PATCH 08/22] io: Add new bytecount test --- io/io/test/CMakeLists.txt | 4 ++ io/io/test/testByteCount.C | 119 +++++++++++++++++++++++++++++++++++ io/io/test/testByteCount.ref | 2 + 3 files changed, 125 insertions(+) create mode 100644 io/io/test/testByteCount.C create mode 100644 io/io/test/testByteCount.ref diff --git a/io/io/test/CMakeLists.txt b/io/io/test/CMakeLists.txt index 2e9efbd370683..b65a1886a6d17 100644 --- a/io/io/test/CMakeLists.txt +++ b/io/io/test/CMakeLists.txt @@ -40,3 +40,7 @@ endif() # ROOT_EXECUTABLE(TMapFileTest TMapFileTest.cxx LIBRARIES RIO Hist New) # ROOT_ADD_TEST(io-io-test-TMapFileTest COMMAND TMapFileTest complete) #endif() + +ROOTTEST_ADD_TEST(testLargeByteCounts + MACRO testByteCount.C + OUTREF testByteCount.ref) diff --git a/io/io/test/testByteCount.C b/io/io/test/testByteCount.C new file mode 100644 index 0000000000000..4c9af3f9707df --- /dev/null +++ b/io/io/test/testByteCount.C @@ -0,0 +1,119 @@ +{ + int errors = 0; + int expectedByteCounts = 1; + + // TBufferFile currently reject size larger than 2GB. + // SetBufferOffset does not check against the size, + // so we can provide and use a larger buffer. + std::vector databuffer{}; + databuffer.reserve( 4*1024*1024*1024ll ); + TBufferFile b(TBuffer::kWrite, 2*1024*1024*1024ll-100, databuffer.data(), false /* don't adopt */); + { + // Regular object at offset 0 + UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); + b.SetBufferOffset(1000); + b.SetByteCount(R__c, kTRUE); + } + { + // Regular object + UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); + b.SetBufferOffset(2000); + b.SetByteCount(R__c, kTRUE); + } + { + // Object larger than 1GB + UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); + b.SetBufferOffset(4000+1*1024*1024*1024ll); + b.SetByteCount(R__c, kTRUE); + } + { + // Regular object located past 1GB + UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); + b.SetBufferOffset(8000+1*1024*1024*1024ll); + b.SetByteCount(R__c, kTRUE); + } + { + ++expectedByteCounts; + // Object larger than 1GB start after 1GB + // NOTE: this does not yet fit, we are writing past the end. + // Need to lift the 2GB limit for TBuffer first. + // However the lifting might be temporary, so this might need to be + // moved to a test that stored objects in a TFile. + UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); + b.SetBufferOffset(12000+2*1024*1024*1024ll); + b.SetByteCount(R__c, kTRUE); + } + + + // To make a copy instead of using the const references: + auto bytecounts{ b.GetByteCounts() }; + if (bytecounts.size() != expectedByteCounts) { + ++errors; + std::cerr << "The number of bytecount is not as expected (1), it is " << bytecounts.size() << '\n'; + std::cerr << "The full list is:\n"; + for(auto bc : bytecounts) + std::cerr << "values: " << bc.first << " , " << bc.second << '\n'; + } + + // Rewind. Other code use Reset instead of SetBufferOffset + b.SetReadMode(); + b.Reset(); + b.SetByteCounts(std::move(bytecounts)); + + UInt_t R__s = 0; + UInt_t R__c = 0; + { + // Regular object at offset 0 + auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); + b.SetBufferOffset(1000); + auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); + if (res != 0) { + ++errors; + // We can assume there as already an error message in CheckByCount + } + } + { + // Regular object + auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); + b.SetBufferOffset(2000); + auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); + if (res != 0) { + ++errors; + // We can assume there as already an error message in CheckByCount + } + } + { + // Object larger than 1GB + auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); + b.SetBufferOffset(4000+1*1024*1024*1024ll); + auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); + if (res != 0) { + ++errors; + // We can assume there as already an error message in CheckByCount + } + } + { + // Regular object located past 1GB + auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); + b.SetBufferOffset(8000+1*1024*1024*1024ll); + auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); + if (res != 0) { + ++errors; + // We can assume there as already an error message in CheckByCount + } + } + { + // Object larger than 1GB start after 1GB + // NOTE: this does not yet fit. + auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); + b.SetBufferOffset(12000+2*1024*1024*1024ll); + auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); + if (res != 0) { + ++errors; + // We can assume there as already an error message in CheckByCount + } + } + + std::cerr << "The end.\n"; + return errors; +} diff --git a/io/io/test/testByteCount.ref b/io/io/test/testByteCount.ref new file mode 100644 index 0000000000000..a5a2b78b46929 --- /dev/null +++ b/io/io/test/testByteCount.ref @@ -0,0 +1,2 @@ +Processing io/io/test/testByteCount.C... +The end. From 446708883faaed65e37bddd8184431d7d646ce57 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 11 Dec 2025 12:49:44 -0600 Subject: [PATCH 09/22] io: Suppress error message about large byte count --- io/io/src/TBufferFile.cxx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index fc28af2c82be7..f0d0a06064dc6 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -374,8 +374,10 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) tobuf(buf, cnt | kByteCountMask); if (cnt >= kMaxMapCount) { - Error("WriteByteCount", "bytecount too large (more than %d)", kMaxMapCount); - // exception + // NOTE: This should now be unreachable. + Fatal("WriteByteCount", + "Control flow error, code should be unreachable and wrote a bytecount that is too large (more than %d)", + kMaxMapCount); } } @@ -3334,7 +3336,11 @@ void TBufferFile::StreamObject(TObject *obj) void TBufferFile::CheckCount(UInt_t offset) { - if (IsWriting()) { + // FIXME: + // We could continue to issue the error for cases where we don't want to + // support storing more than 1GB in a single TBufferFile. + const bool bufferLimitedToMaxMapCount = false; + if (bufferLimitedToMaxMapCount && IsWriting()) { if (offset >= kMaxMapCount) { Error("CheckCount", "buffer offset too large (larger than %d)", kMaxMapCount); // exception From 7a9e8691dcff7da658eef0f202aa999e2b3d8c44 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 11 Dec 2025 13:02:11 -0600 Subject: [PATCH 10/22] [NFC] io white space / byte count related --- io/io/inc/TBufferFile.h | 2 +- io/io/src/TBufferFile.cxx | 5 +++-- io/io/test/testByteCount.C | 21 ++++++++++----------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index ba6d0be4d881d..143f8ac374a69 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -117,7 +117,7 @@ class TBufferFile : public TBufferIO { TObject *ReadObject(const TClass *cl) override; - const ByteCountFinder_t& GetByteCounts() const { return fByteCounts; } + const ByteCountFinder_t &GetByteCounts() const { return fByteCounts; } void SetByteCounts(ByteCountFinder_t &&byteCounts) { fByteCounts = std::move(byteCounts); } void ResetMap() override; diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index f0d0a06064dc6..0be3f74ac63fa 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -340,7 +340,7 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) // which uses the stack to get the position and call the new one. // This (of course) also requires that we do the 'same' to the WriteVersion // routines. - R__ASSERT( !fByteCountStack.empty() ); + R__ASSERT(!fByteCountStack.empty()); if (cntpos == kMaxInt) { cntpos = fByteCountStack.back(); } @@ -441,7 +441,8 @@ Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const T if ( ((char *)endpos) > fBufMax ) { offset = fBufMax-fBufCur; Error("CheckByteCount", - "Byte count probably corrupted around buffer position %llu:\n\tByte count is %llu while the buffer size is %lld", + "Byte count probably corrupted around buffer position %llu:\n\tByte count is %llu while the buffer size " + "is %lld", startpos, bcnt, offset); fBufCur = fBufMax; diff --git a/io/io/test/testByteCount.C b/io/io/test/testByteCount.C index 4c9af3f9707df..b152e3700aa75 100644 --- a/io/io/test/testByteCount.C +++ b/io/io/test/testByteCount.C @@ -6,8 +6,8 @@ // SetBufferOffset does not check against the size, // so we can provide and use a larger buffer. std::vector databuffer{}; - databuffer.reserve( 4*1024*1024*1024ll ); - TBufferFile b(TBuffer::kWrite, 2*1024*1024*1024ll-100, databuffer.data(), false /* don't adopt */); + databuffer.reserve(4 * 1024 * 1024 * 1024ll); + TBufferFile b(TBuffer::kWrite, 2 * 1024 * 1024 * 1024ll - 100, databuffer.data(), false /* don't adopt */); { // Regular object at offset 0 UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); @@ -23,13 +23,13 @@ { // Object larger than 1GB UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); - b.SetBufferOffset(4000+1*1024*1024*1024ll); + b.SetBufferOffset(4000 + 1 * 1024 * 1024 * 1024ll); b.SetByteCount(R__c, kTRUE); } { // Regular object located past 1GB UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); - b.SetBufferOffset(8000+1*1024*1024*1024ll); + b.SetBufferOffset(8000 + 1 * 1024 * 1024 * 1024ll); b.SetByteCount(R__c, kTRUE); } { @@ -40,18 +40,17 @@ // However the lifting might be temporary, so this might need to be // moved to a test that stored objects in a TFile. UInt_t R__c = b.WriteVersion(TExMap::Class(), kTRUE); - b.SetBufferOffset(12000+2*1024*1024*1024ll); + b.SetBufferOffset(12000 + 2 * 1024 * 1024 * 1024ll); b.SetByteCount(R__c, kTRUE); } - // To make a copy instead of using the const references: - auto bytecounts{ b.GetByteCounts() }; + auto bytecounts{b.GetByteCounts()}; if (bytecounts.size() != expectedByteCounts) { ++errors; std::cerr << "The number of bytecount is not as expected (1), it is " << bytecounts.size() << '\n'; std::cerr << "The full list is:\n"; - for(auto bc : bytecounts) + for (auto bc : bytecounts) std::cerr << "values: " << bc.first << " , " << bc.second << '\n'; } @@ -85,7 +84,7 @@ { // Object larger than 1GB auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); - b.SetBufferOffset(4000+1*1024*1024*1024ll); + b.SetBufferOffset(4000 + 1 * 1024 * 1024 * 1024ll); auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); if (res != 0) { ++errors; @@ -95,7 +94,7 @@ { // Regular object located past 1GB auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); - b.SetBufferOffset(8000+1*1024*1024*1024ll); + b.SetBufferOffset(8000 + 1 * 1024 * 1024 * 1024ll); auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); if (res != 0) { ++errors; @@ -106,7 +105,7 @@ // Object larger than 1GB start after 1GB // NOTE: this does not yet fit. auto version = b.ReadVersion(&R__s, &R__c, TExMap::Class()); - b.SetBufferOffset(12000+2*1024*1024*1024ll); + b.SetBufferOffset(12000 + 2 * 1024 * 1024 * 1024ll); auto res = b.CheckByteCount(R__s, R__c, TExMap::Class()); if (res != 0) { ++errors; From 16a863b2230f3521f3cf92dacd7d0ea75b782bea Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 5 Feb 2026 19:12:43 +0100 Subject: [PATCH 11/22] NFC io: fix doc typo --- io/io/src/TBufferFile.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 0be3f74ac63fa..c9f982a872616 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -324,7 +324,7 @@ void TBufferFile::WriteCharStar(char *s) //////////////////////////////////////////////////////////////////////////////// /// Set byte count at position cntpos in the buffer. Generate warning if -/// count larger than kMaxMapCount. The count is excluded its own size. +/// count larger than kMaxMapCount. The count is excluding its own size. /// \note If underflow or overflow, an Error ir raised (stricter checks in Debug mode) void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) From 543515b04de6468ee5904ec77560080053b5979a Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 5 Feb 2026 19:15:54 +0100 Subject: [PATCH 12/22] io: doc clarifications - bytecount related --- io/io/src/TBufferFile.cxx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index c9f982a872616..3d32ed85ad109 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -415,6 +415,7 @@ Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const T return 0; Long64_t offset = 0; + // End position is buffer location + start position + byte count + size of byte count field Longptr_t endpos = Longptr_t(fBuffer) + startpos + bcnt + sizeof(UInt_t); if (Longptr_t(fBufCur) != endpos) { @@ -2800,6 +2801,8 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) bcnt = 0; } else { fVersion = 1; + // When objTag is not used, the caller is not interested in the byte + // count and will not (can not) call CheckByteCount. if (objTag) fByteCountStack.push_back(fBufCur - fBuffer); startpos = UInt_t(fBufCur-fBuffer); @@ -2978,6 +2981,9 @@ void TBufferFile::SkipVersion(const TClass *cl) //////////////////////////////////////////////////////////////////////////////// /// Read class version from I/O buffer. +/// If passing startpos and bcnt, CheckByteCount must be called later with +/// the same startpos and bcnt (this is needed to properly handle the byte +/// count stack used to support very large buffers) Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass *cl) { @@ -3108,6 +3114,15 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass //////////////////////////////////////////////////////////////////////////////// /// Read class version from I/O buffer, when the caller knows for sure that /// there is no checksum written/involved. +/// +/// This routine can be used from custom streamers when it is known that the +/// class was always versioned (and thus never stored a checksum within the buffer). +/// This allows to disambiguate the case where the class used to have a version +/// number equal to zero and did not save a byte count and is now versioned. +/// +/// When reading the version number being zero, without the byte count we have +/// no way to guess whether the class was version un-versioned or had previously +/// a version number equal to zero. Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) { @@ -3430,9 +3445,8 @@ UInt_t TBufferFile::CheckObject(UInt_t offset, const TClass *cl, Bool_t readClas /// Reserve space for a leading byte count and return the position where to /// store the byte count value. /// -/// \param[in] mask The mask to apply to the placeholder value (default kByteCountMask) /// \return The position (cntpos) where the byte count should be stored later, -/// or 0 if the position exceeds kMaxInt +/// or kOverflowPosition if the position exceeds kMaxCountPosition UInt_t TBufferFile::ReserveByteCount() { From ed19201196cee94c5c776cd6e894868193df2dcd Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Thu, 5 Feb 2026 19:28:27 +0100 Subject: [PATCH 13/22] io: Clarify byte count related limits --- io/io/src/TBufferFile.cxx | 78 ++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 3d32ed85ad109..a304fb0093196 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -15,6 +15,21 @@ \ingroup IO The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket. + +Limits: +Byte Count positions (refered to as `cntpos` or `startpos` in the code) + - Internally they are passed as a ULong64_t + - In legacy user code they are held in UInt_t variables (See type used in + TBufferFile::WriteVersion and TBufferFile::ReadVersion) + - The positions passed by value are limited to 4GB (kOverflowPosition) + and the positions are held in fByteCountStack but retrieved only when + higher than 4GB (kOverflowCount). +Byte Count values: + - Internally they are passed as a ULong64_t + - In legacy user code they are held in UInt_t variables (See type used in + TBufferFile::WriteVersion and TBufferFile::ReadVersion) + - The values passed by value are limited to 1GB (kMaxMapCount) + - The values larger than kMaxMapCount are held in fByteCounts. */ #include @@ -46,15 +61,18 @@ The concrete implementation of TBuffer for writing/reading to/from a ROOT file o #include "Bswapcpy.h" #endif +constexpr UInt_t kOverflowPosition = 0xFFFFFFFF; +constexpr UInt_t kOverflowCount = 0xFFFFFFFF; +constexpr UInt_t kMaxCountPosition = 0xFFFFFFFE; // We reserve the highest value to mark overflow positions -const UInt_t kNewClassTag = 0xFFFFFFFF; -const UInt_t kClassMask = 0x80000000; // OR the class index with this -const UInt_t kByteCountMask = 0x40000000; // OR the byte count with this -const UInt_t kMaxMapCount = 0x3FFFFFFE; // last valid fMapCount and byte count -const Version_t kByteCountVMask = 0x4000; // OR the version byte count with this -const Version_t kMaxVersion = 0x3FFF; // highest possible version number -const Int_t kMapOffset = 2; // first 2 map entries are taken by null obj and self obj - +constexpr UInt_t kNewClassTag = 0xFFFFFFFF; +constexpr UInt_t kClassMask = 0x80000000; // OR the class index with this +constexpr UInt_t kByteCountMask = 0x40000000; // OR the byte count with this +constexpr UInt_t kMaxMapCount = 0x3FFFFFFE; // last valid fMapCount and byte count +constexpr UInt_t kMaxRecordByteCount = kMaxMapCount; // last valid byte count +constexpr Version_t kByteCountVMask = 0x4000; // OR the version byte count with this +constexpr Version_t kMaxVersion = 0x3FFF; // highest possible version number +constexpr Int_t kMapOffset = 2; // first 2 map entries are taken by null obj and self obj //////////////////////////////////////////////////////////////////////////////// @@ -323,13 +341,13 @@ void TBufferFile::WriteCharStar(char *s) } //////////////////////////////////////////////////////////////////////////////// -/// Set byte count at position cntpos in the buffer. Generate warning if -/// count larger than kMaxMapCount. The count is excluding its own size. +/// Set byte count at position cntpos in the buffer. +/// The count is excluding its own size. /// \note If underflow or overflow, an Error ir raised (stricter checks in Debug mode) void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) { - assert( cntpos <= kMaxUInt && (sizeof(UInt_t) + cntpos) < static_cast(fBufCur - fBuffer) + assert( cntpos <= kOverflowPosition && (sizeof(UInt_t) + cntpos) < static_cast(fBufCur - fBuffer) && (fBufCur >= fBuffer) && static_cast(fBufCur - fBuffer) <= std::numeric_limits::max() && "Byte count position is after the end of the buffer"); @@ -341,14 +359,15 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) // This (of course) also requires that we do the 'same' to the WriteVersion // routines. R__ASSERT(!fByteCountStack.empty()); - if (cntpos == kMaxInt) { + if (cntpos == kOverflowPosition) { + // The position is above 4GB but was cached using a 32 bit variable. cntpos = fByteCountStack.back(); } fByteCountStack.pop_back(); // if we are not in the same TKey chunk or if the cntpos is too large to fit in UInt_t // let's postpone the writing of the byte count const ULong64_t full_cnt = ULong64_t(fBufCur - fBuffer) - cntpos - sizeof(UInt_t); - if (full_cnt >= kMaxMapCount) { + if (full_cnt >= kMaxRecordByteCount) { fByteCounts[cntpos] = full_cnt; return; } @@ -373,11 +392,11 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) } else tobuf(buf, cnt | kByteCountMask); - if (cnt >= kMaxMapCount) { + if (cnt >= kMaxRecordByteCount) { // NOTE: This should now be unreachable. Fatal("WriteByteCount", "Control flow error, code should be unreachable and wrote a bytecount that is too large (more than %d)", - kMaxMapCount); + kMaxRecordByteCount); } } @@ -391,12 +410,13 @@ void TBufferFile::SetByteCount(ULong64_t cntpos, Bool_t packInVersion) Long64_t TBufferFile::CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char *classname) { - R__ASSERT(!fByteCountStack.empty()); - if (startpos == kMaxInt) { - // The position is above 1GB and was cached using a 32 bit variable. + R__ASSERT(!fByteCountStack.empty() && startpos <= kOverflowPosition && bcnt <= kOverflowCount + && "Byte count stack is empty or invalid startpos/bcnt"); + if (startpos == kOverflowPosition) { + // The position is above 4GB but was cached using a 32 bit variable. startpos = fByteCountStack.back(); } - if (bcnt == kMaxInt) { + if (bcnt == kOverflowCount) { // in case we are checking a byte count for which we postponed // the writing because it was too large, we retrieve it now auto it = fByteCounts.find(startpos); @@ -2992,7 +3012,7 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass if (startpos) { // before reading object save start position auto full_startpos = fBufCur - fBuffer; - *startpos = full_startpos < kMaxInt ? UInt_t(full_startpos) : kMaxInt; + *startpos = full_startpos <= kMaxCountPosition ? UInt_t(full_startpos) : kOverflowPosition; if (bcnt) fByteCountStack.push_back(full_startpos); } @@ -3029,10 +3049,10 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass if (*bcnt == 0) { // The byte count was stored but is zero, this means the data // did not fit and thus we stored it in 'fByteCounts' instead. - // Mark this case by setting startpos to kMaxInt. - *bcnt = kMaxInt; + // Mark this case by setting startpos to kOverflowCount. + *bcnt = kOverflowCount; if (startpos) - *startpos = kMaxInt; + *startpos = kOverflowPosition; } } } @@ -3131,7 +3151,7 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) if (startpos) { // before reading object save start position auto full_startpos = fBufCur - fBuffer; - *startpos = full_startpos < kMaxInt ? UInt_t(full_startpos) : kMaxInt; + *startpos = full_startpos < kMaxCountPosition ? UInt_t(full_startpos) : kOverflowPosition; if (bcnt) fByteCountStack.push_back(full_startpos); } @@ -3168,10 +3188,10 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) if (*bcnt == 0) { // The byte count was stored but is zero, this means the data // did not fit and thus we stored it in 'fByteCounts' instead. - // Mark this case by setting startpos to kMaxInt. - *bcnt = kMaxInt; + // Mark this case by setting startpos to kOverflowCount. + *bcnt = kOverflowCount; if (startpos) - *startpos = kMaxInt; + *startpos = kOverflowPosition; } } } @@ -3357,7 +3377,7 @@ void TBufferFile::CheckCount(UInt_t offset) // support storing more than 1GB in a single TBufferFile. const bool bufferLimitedToMaxMapCount = false; if (bufferLimitedToMaxMapCount && IsWriting()) { - if (offset >= kMaxMapCount) { + if (offset > kMaxRecordByteCount) { // We have kMaxMapCount == kMaxRecordByteCount Error("CheckCount", "buffer offset too large (larger than %d)", kMaxMapCount); // exception } @@ -3454,7 +3474,7 @@ UInt_t TBufferFile::ReserveByteCount() auto full_cntpos = fBufCur - fBuffer; fByteCountStack.push_back(full_cntpos); *this << (UInt_t)kByteCountMask; // placeholder for byte count - return full_cntpos < kMaxInt ? full_cntpos : kMaxInt; + return full_cntpos <= kMaxCountPosition ? full_cntpos : kOverflowPosition; } //////////////////////////////////////////////////////////////////////////////// From 588b29e6f2ed80bd37eaafd9ea2e14336420b1b2 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sun, 8 Feb 2026 15:00:57 +0100 Subject: [PATCH 14/22] io: ReadVersion should always take both position and byte count --- io/io/src/TBufferFile.cxx | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index a304fb0093196..92bacafdcd231 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -3007,14 +3007,15 @@ void TBufferFile::SkipVersion(const TClass *cl) Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass *cl) { + assert((!startpos && !bcnt) || (startpos && bcnt)); // both or none should be set + Version_t version; if (startpos) { // before reading object save start position auto full_startpos = fBufCur - fBuffer; *startpos = full_startpos <= kMaxCountPosition ? UInt_t(full_startpos) : kOverflowPosition; - if (bcnt) - fByteCountStack.push_back(full_startpos); + fByteCountStack.push_back(full_startpos); } // read byte count (older files don't have byte count) @@ -3039,11 +3040,11 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass v.cnt = 0; } if (bcnt) { + // We also have (asserted) that (startpos != nullptr) if (!v.cnt) { // no byte count stored *bcnt = 0; - if (startpos) // Undo the push_back only if it happened. - fByteCountStack.pop_back(); + fByteCountStack.pop_back(); } else { *bcnt = (v.cnt & ~kByteCountMask); if (*bcnt == 0) { @@ -3051,8 +3052,7 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass // did not fit and thus we stored it in 'fByteCounts' instead. // Mark this case by setting startpos to kOverflowCount. *bcnt = kOverflowCount; - if (startpos) - *startpos = kOverflowPosition; + *startpos = kOverflowPosition; } } } @@ -3146,14 +3146,15 @@ Version_t TBufferFile::ReadVersion(UInt_t *startpos, UInt_t *bcnt, const TClass Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) { + assert((!startpos && !bcnt) || (startpos && bcnt)); // both or none should be set + Version_t version; if (startpos) { // before reading object save start position auto full_startpos = fBufCur - fBuffer; *startpos = full_startpos < kMaxCountPosition ? UInt_t(full_startpos) : kOverflowPosition; - if (bcnt) - fByteCountStack.push_back(full_startpos); + fByteCountStack.push_back(full_startpos); } // read byte count (older files don't have byte count) @@ -3181,8 +3182,7 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) if (!v.cnt) { // no byte count stored *bcnt = 0; - if (startpos) // Undo the push_back only if it happened. - fByteCountStack.pop_back(); + fByteCountStack.pop_back(); } else { *bcnt = (v.cnt & ~kByteCountMask); if (*bcnt == 0) { @@ -3190,8 +3190,7 @@ Version_t TBufferFile::ReadVersionNoCheckSum(UInt_t *startpos, UInt_t *bcnt) // did not fit and thus we stored it in 'fByteCounts' instead. // Mark this case by setting startpos to kOverflowCount. *bcnt = kOverflowCount; - if (startpos) - *startpos = kOverflowPosition; + *startpos = kOverflowPosition; } } } From ab243af7d49d0f3f66e3691fc6ff035c23387d9c Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Sun, 8 Feb 2026 17:34:45 +0100 Subject: [PATCH 15/22] io: Correct handling of byte count pos in TBufferFile::ReadObjectAny --- io/io/src/TBufferFile.cxx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 92bacafdcd231..fbe038bff88e5 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -2593,7 +2593,8 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) InitMap(); // before reading object save start position - UInt_t startpos = UInt_t(fBufCur-fBuffer); + ULong64_t startpos = static_cast(fBufCur-fBuffer); + ULong64_t cntpos = startpos <= kMaxCountPosition ? startpos : kOverflowPosition; // attempt to load next object as TClass clCast UInt_t tag; // either tag or byte count @@ -2613,7 +2614,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) Error("ReadObject", "got object of wrong class! requested %s but got %s", clCast->GetName(), clRef->GetName()); - CheckByteCount(startpos, tag, (TClass *)nullptr); // avoid mis-leading byte count error message + CheckByteCount(cntpos, tag, (TClass *)nullptr); // avoid mis-leading byte count error message return 0; // We better return at this point } baseOffset = 0; // For now we do not support requesting from a class that is the base of one of the class for which there is transformation to .... @@ -2628,7 +2629,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) //we cannot mix a compiled class with an emulated class in the inheritance Error("ReadObject", "trying to read an emulated class (%s) to store in a compiled pointer (%s)", clRef->GetName(),clCast->GetName()); - CheckByteCount(startpos, tag, (TClass *)nullptr); // avoid mis-leading byte count error message + CheckByteCount(cntpos, tag, (TClass *)nullptr); // avoid mis-leading byte count error message return 0; } } @@ -2640,7 +2641,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) obj = (char *) (Longptr_t)fMap->GetValue(startpos+kMapOffset); if (obj == (void*) -1) obj = nullptr; if (obj) { - CheckByteCount(startpos, tag, (TClass *)nullptr); + CheckByteCount(cntpos, tag, (TClass *)nullptr); return (obj + baseOffset); } } @@ -2652,7 +2653,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) MapObject((TObject*) -1, startpos+kMapOffset); else MapObject((void*)nullptr, nullptr, fMapCount); - CheckByteCount(startpos, tag, (TClass *)nullptr); + CheckByteCount(cntpos, tag, (TClass *)nullptr); return 0; } @@ -2711,7 +2712,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) // let the object read itself clRef->Streamer( obj, *this, clOnfile ); - CheckByteCount(startpos, tag, clRef); + CheckByteCount(cntpos, tag, clRef); } return obj+baseOffset; From 8cfe2ddb4ffc0d4b9e153eb0f401289250c59d54 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 10 Dec 2025 13:18:38 -0600 Subject: [PATCH 16/22] io: add test for long range references For now, the testing of the long range references is disabled. --- io/io/test/InnerReferencesTests.cxx | 133 ++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 io/io/test/InnerReferencesTests.cxx diff --git a/io/io/test/InnerReferencesTests.cxx b/io/io/test/InnerReferencesTests.cxx new file mode 100644 index 0000000000000..eef112d289e92 --- /dev/null +++ b/io/io/test/InnerReferencesTests.cxx @@ -0,0 +1,133 @@ +#include "TBufferFile.h" +#include "TClass.h" +#include "TMacro.h" +#include "TNamed.h" +#include "TProtoClass.h" + +#include "gtest/gtest.h" + +namespace { + +struct ReadResult { + int fError = 0; + TObject *fObj = nullptr; +}; + +void Update(int &errors, std::unique_ptr &obj, const ReadResult &res) +{ + errors += res.fError; + obj.reset(res.fObj); +} + +ReadResult ReadAndCheck(TBuffer &b, TClass *cl, TObject *ident = nullptr) +{ + ReadResult result; + + b >> result.fObj; + + EXPECT_NE(result.fObj, nullptr) + << "Failed to read object of class '" << cl->GetName() << "'"; + if (!result.fObj) { + result.fError = 1; + return result; + } + + EXPECT_EQ(result.fObj->IsA(), cl) + << "Expected class '" << cl->GetName() + << "' but read '" << result.fObj->IsA()->GetName() << "'"; + if (result.fObj->IsA() != cl) { + result.fError = 2; + return result; + } + + if (ident) { + EXPECT_EQ(ident, result.fObj); + if (ident != result.fObj) { + result.fError = 3; + return result; + } + } + + return result; +} + +} // anonymous namespace + +TEST(TBufferFileInnerReferences, LargeOffsetsAndReferences) +{ + int errors = 0; + + auto n0 = std::make_unique("n0", "At start"); + auto n1 = std::make_unique("n1", "Below 1G"); + auto n2 = std::make_unique("n2", "Over 1G"); + auto m1 = std::make_unique("m1", "Below 1G"); + auto m2 = std::make_unique("m2", "Over 1G"); + auto c1 = std::make_unique(); // Only over 1G + auto c2 = std::make_unique(); // Also over 1G + + // TBufferFile currently rejects sizes larger than 2GB. + // SetBufferOffset does not check against the size, + // so we can provide and use a larger buffer. + std::vector databuffer{}; + databuffer.reserve(4ull * 1024 * 1024 * 1024); + TBufferFile b(TBuffer::kWrite, 2ull * 1024 * 1024 * 1024 - 100, databuffer.data(), false /* don't adopt */); + + b << n0.get(); + b.SetBufferOffset(512ull * 1024 * 1024); + b << n1.get(); + b << m1.get(); + b.SetBufferOffset(1536ull * 1024 * 1024); + b << n2.get(); + b << m2.get(); + b << c1.get(); + b << c2.get(); + + // Those should all be references. + b << n0.get(); + b << n1.get(); + b << m1.get(); + b << n2.get(); + b << m2.get(); + b << c1.get(); + b << c2.get(); + + // To make a copy instead of using the const references: + auto bytecounts = b.GetByteCounts(); + // Rewind. Other code uses Reset instead of SetBufferOffset + b.SetReadMode(); + b.Reset(); + b.SetByteCounts(std::move(bytecounts)); + + std::unique_ptr rn0; + std::unique_ptr rn1; + std::unique_ptr rn2; + std::unique_ptr rm1; + std::unique_ptr rm2; + std::unique_ptr rc1; + std::unique_ptr rc2; + + Update(errors, rn0, ReadAndCheck(b, n0->IsA())); + + b.SetBufferOffset(512ull * 1024 * 1024); + Update(errors, rn1, ReadAndCheck(b, n1->IsA())); + Update(errors, rm1, ReadAndCheck(b, m1->IsA())); + + b.SetBufferOffset(1536ull * 1024 * 1024); + Update(errors, rn2, ReadAndCheck(b, n2->IsA())); + Update(errors, rm2, ReadAndCheck(b, m2->IsA())); + Update(errors, rc1, ReadAndCheck(b, c1->IsA())); + Update(errors, rc2, ReadAndCheck(b, c2->IsA())); + + // Reference and Class name below 1G + errors += ReadAndCheck(b, n0->IsA(), rn0.get()).fError; + errors += ReadAndCheck(b, n1->IsA(), rn1.get()).fError; + errors += ReadAndCheck(b, m1->IsA(), rm1.get()).fError; + if (0) { // These require implementing proper support for long range references. + errors += ReadAndCheck(b, n2->IsA(), rn2.get()).fError; // Reference over 1G + errors += ReadAndCheck(b, m2->IsA(), rm2.get()).fError; // Reference over 1G + errors += ReadAndCheck(b, c1->IsA(), rc1.get()).fError; // Class and reference over 1G + errors += ReadAndCheck(b, c2->IsA(), rc2.get()).fError; // Class and reference over 1G + } + + EXPECT_EQ(errors, 0); +} From db6ab45524a2424498120329490bd201a1b6ce06 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Fri, 12 Dec 2025 14:31:31 -0600 Subject: [PATCH 17/22] io: add comment about 32/64 bits --- io/io/src/TBufferFile.cxx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index fbe038bff88e5..a4f8e66c1bc74 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -2753,6 +2753,7 @@ void TBufferFile::WriteObjectClass(const void *actualObjectStart, const TClass * UInt_t objIdx = UInt_t(idx); // save index of already stored object + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits *this << objIdx; } else { @@ -2816,6 +2817,7 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) return cl; } UInt_t bcnt, tag, startpos = 0; + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits *this >> bcnt; if (!(bcnt & kByteCountMask) || bcnt == kNewClassTag) { tag = bcnt; @@ -2909,6 +2911,9 @@ void TBufferFile::WriteClass(const TClass *cl) UInt_t clIdx = UInt_t(idx); // save index of already stored class + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits + // FIXME/INCORRECTNESS: if clIdx > 0x3FFFFFFF the control bit (2nd highest bit) will be wrong + // FIXME/INCORRECTNESS: similarly if clIdx > kClassMask (2GB) the code will be wrong *this << (clIdx | kClassMask); } else { From da28f8f219e9204d351b48b6a654f3485e68074b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 15 Dec 2025 13:08:25 -0600 Subject: [PATCH 18/22] NFC io: white space --- io/io/src/TBufferFile.cxx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index a4f8e66c1bc74..070041b0076f1 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -2834,7 +2834,8 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) // in case tag is object tag return tag if (!(tag & kClassMask)) { - if (objTag) *objTag = tag; + if (objTag) + *objTag = tag; return 0; } @@ -2885,10 +2886,12 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) } // return bytecount in objTag - if (objTag) *objTag = (bcnt & ~kByteCountMask); + if (objTag) + *objTag = (bcnt & ~kByteCountMask); // case of unknown class - if (!cl) cl = (TClass*)-1; + if (!cl) + cl = (TClass*)-1; return cl; } From 3495676d96ca6acc9a096ede3e3175fc20ba3860 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 15 Dec 2025 13:10:08 -0600 Subject: [PATCH 19/22] io: Add support for long range references (objects and class names) References for class names and objects are stored in 64bits whenever they are located past 1GB. This is the 'only' option as there are no control bits left to distinguish between a 32bits and a 64bits reference. --- io/io/inc/TBufferFile.h | 2 +- io/io/src/TBufferFile.cxx | 88 +++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 143f8ac374a69..873e1ba085988 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -71,7 +71,7 @@ class TBufferFile : public TBufferIO { Long64_t CheckByteCount(ULong64_t startpos, ULong64_t bcnt, const TClass *clss, const char* classname); void CheckCount(UInt_t offset) override; - UInt_t CheckObject(UInt_t offset, const TClass *cl, Bool_t readClass = kFALSE); + UInt_t CheckObject(ULong64_t offset, const TClass *cl, Bool_t readClass = kFALSE); UInt_t ReserveByteCount(); void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse) override; diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index 070041b0076f1..c1b44274aa692 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -74,6 +74,9 @@ constexpr Version_t kByteCountVMask = 0x4000; // OR the version byte coun constexpr Version_t kMaxVersion = 0x3FFF; // highest possible version number constexpr Int_t kMapOffset = 2; // first 2 map entries are taken by null obj and self obj +// constexpr ULong64_t kMaxLongRange = 0x0FFFFFFFFFFFFFFE; // We reserve the 4 highest bits for flags, currently only 2 are in use. +constexpr ULong64_t kLongRangeClassMask = 0x8000000000000000; // OR the class index with this +// constexpr ULong64_t kLongRangeByteCountMask = 0x4000000000000000; // OR the byte count with this //////////////////////////////////////////////////////////////////////////////// /// Thread-safe check on StreamerInfos of a TClass @@ -2816,11 +2819,28 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) cl = (TClass*)-1; return cl; } - UInt_t bcnt, tag, startpos = 0; + UInt_t bcnt; + Long64_t tag64, startpos = 0; + const bool shortRange = (fBufCur - fBuffer) <= kMaxMapCount; + bool isNewClassTag = false; + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits *this >> bcnt; - if (!(bcnt & kByteCountMask) || bcnt == kNewClassTag) { - tag = bcnt; + if (bcnt == kNewClassTag) { + isNewClassTag = true; + tag64 = 0; + bcnt = 0; + } else if (!(bcnt & kByteCountMask)) { + if (R__likely(shortRange)) { + tag64 = bcnt; + } else { + // Two implementation choices: + // 1) rewind and read full 64-bit value + // 2) use the already read 32-bits, read the rest and combine + UInt_t low32; + *this >> low32; + tag64 = (static_cast(bcnt) << 32) | low32; + } bcnt = 0; } else { fVersion = 1; @@ -2828,18 +2848,27 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) // count and will not (can not) call CheckByteCount. if (objTag) fByteCountStack.push_back(fBufCur - fBuffer); - startpos = UInt_t(fBufCur-fBuffer); - *this >> tag; + startpos = static_cast(fBufCur - fBuffer); + if (R__likely(shortRange)) { + UInt_t tag; + *this >> tag; + tag64 = tag; + } else { + *this >> tag64; + } } + const bool isClassTag = shortRange ? (tag64 & kClassMask) : (tag64 & kLongRangeClassMask); + // in case tag is object tag return tag - if (!(tag & kClassMask)) { + if (!isClassTag) { + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits if (objTag) - *objTag = tag; + *objTag = tag64; return 0; } - if (tag == kNewClassTag) { + if (isNewClassTag) { // got a new class description followed by a new object // (class can be 0 if class dictionary is not found, in that @@ -2858,14 +2887,14 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) } else { // got a tag to an already seen class - UInt_t clTag = (tag & ~kClassMask); + ULong64_t clTag = shortRange ? (tag64 & ~kClassMask) : (tag64 & ~kLongRangeClassMask); if (fVersion > 0) { clTag += fDisplacement; clTag = CheckObject(clTag, clReq, kTRUE); } else { if (clTag == 0 || clTag > (UInt_t)fMap->GetSize()) { - Error("ReadClass", "illegal class tag=%d (0GetSize()); // exception } @@ -2907,22 +2936,29 @@ void TBufferFile::WriteClass(const TClass *cl) ULong_t hash = Void_Hash(cl); UInt_t slot; - if ((idx = (ULongptr_t)fMap->GetValue(hash, (Longptr_t)cl,slot)) != 0) { - - // truncation is OK the value we did put in the map is an 30-bit offset - // and not a pointer - UInt_t clIdx = UInt_t(idx); - - // save index of already stored class - // FIXME/TRUNCATION: potential truncation from 64 to 32 bits - // FIXME/INCORRECTNESS: if clIdx > 0x3FFFFFFF the control bit (2nd highest bit) will be wrong - // FIXME/INCORRECTNESS: similarly if clIdx > kClassMask (2GB) the code will be wrong - *this << (clIdx | kClassMask); + if ((idx = (ULongptr_t)fMap->GetValue(hash, (Longptr_t)cl, slot)) != 0) { + const bool shortRange = (fBufCur - fBuffer) <= kMaxMapCount; + if (R__likely(shortRange)) { + // truncation is OK the value we did put in the map is an 30-bit offset + // and not a pointer + UInt_t clIdx = UInt_t(idx); + // save index of already stored class + // FIXME/TRUNCATION: potential truncation from 64 to 32 bits + // FIXME/INCORRECTNESS: if clIdx > 0x3FFFFFFF the control bit (2nd highest bit) will be wrong + // FIXME/INCORRECTNESS: similarly if clIdx > kClassMask (2GB) the code will be wrong + *this << (clIdx | kClassMask); + } else { + // The 64-bit value is stored highest bytes first in the buffer, + // so when reading just the first 32-bits we get the control bits in place. + // This is needed so that the reader can distinguish between references, + // bytecounts, and new class definitions. + ULong64_t clIdx = static_cast(idx); + *this << (clIdx | kLongRangeClassMask); + } } else { - // offset in buffer where class info is written - UInt_t offset = UInt_t(fBufCur-fBuffer); + Long64_t offset = (static_cast(fBufCur-fBuffer)); // save new class tag *this << kNewClassTag; @@ -3398,7 +3434,7 @@ void TBufferFile::CheckCount(UInt_t offset) /// object is -1 then it really does not exist and we return 0. If the object /// exists just return the offset. -UInt_t TBufferFile::CheckObject(UInt_t offset, const TClass *cl, Bool_t readClass) +UInt_t TBufferFile::CheckObject(ULong64_t offset, const TClass *cl, Bool_t readClass) { // in position 0 we always have the reference to the null object if (!offset) return offset; @@ -3451,8 +3487,8 @@ UInt_t TBufferFile::CheckObject(UInt_t offset, const TClass *cl, Bool_t readClas // mark object as really not available fMap->Remove(offset); fMap->Add(offset, -1); - Warning("CheckObject", "reference to object of unavailable class %s, offset=%d" - " pointer will be 0", cl ? cl->GetName() : "TObject",offset); + Warning("CheckObject", "reference to object of unavailable class %s, offset=%llu" + " pointer will be 0", cl ? cl->GetName() : "TObject", offset); offset = 0; } From d2262b7d26df76535119bba0205105486f096ed2 Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Mon, 15 Dec 2025 14:30:53 -0600 Subject: [PATCH 20/22] io: 64 bit/long range references TBufferFile::ReadClass --- core/base/inc/TBuffer.h | 2 +- core/base/src/TString.cxx | 2 +- core/cont/src/TArray.cxx | 2 +- io/io/inc/TBufferFile.h | 2 +- io/io/inc/TBufferJSON.h | 2 +- io/io/src/TBufferFile.cxx | 18 ++++++++++++++---- io/io/src/TBufferJSON.cxx | 2 +- io/io/src/TContainerConverters.cxx | 4 ++-- io/sql/inc/TBufferSQL2.h | 2 +- io/sql/src/TBufferSQL2.cxx | 2 +- io/xml/inc/TBufferXML.h | 2 +- io/xml/src/TBufferXML.cxx | 2 +- 12 files changed, 26 insertions(+), 16 deletions(-) diff --git a/core/base/inc/TBuffer.h b/core/base/inc/TBuffer.h index edafce36448f7..793529b385056 100644 --- a/core/base/inc/TBuffer.h +++ b/core/base/inc/TBuffer.h @@ -150,7 +150,7 @@ class TBuffer : public TObject { virtual TVirtualArray *PopDataCache(); virtual void PushDataCache(TVirtualArray *); - virtual TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) = 0; + virtual TClass *ReadClass(const TClass *cl = nullptr, ULong64_t *objTag = nullptr) = 0; virtual void WriteClass(const TClass *cl) = 0; virtual TObject *ReadObject(const TClass *cl) = 0; diff --git a/core/base/src/TString.cxx b/core/base/src/TString.cxx index 0224eb6461d8e..40861a02e0c21 100644 --- a/core/base/src/TString.cxx +++ b/core/base/src/TString.cxx @@ -1375,7 +1375,7 @@ TString *TString::ReadString(TBuffer &b, const TClass *clReq) // Before reading object save start position UInt_t startpos = UInt_t(b.Length()); - UInt_t tag; + ULong64_t tag; TClass *clRef = b.ReadClass(clReq, &tag); TString *a; diff --git a/core/cont/src/TArray.cxx b/core/cont/src/TArray.cxx index a5283e5523d53..16f9149f943c4 100644 --- a/core/cont/src/TArray.cxx +++ b/core/cont/src/TArray.cxx @@ -47,7 +47,7 @@ TArray *TArray::ReadArray(TBuffer &b, const TClass *clReq) // Before reading object save start position UInt_t startpos = UInt_t(b.Length()); - UInt_t tag; + ULong64_t tag; TClass *clRef = b.ReadClass(clReq, &tag); TArray *a; diff --git a/io/io/inc/TBufferFile.h b/io/io/inc/TBufferFile.h index 873e1ba085988..a11408ead08cf 100644 --- a/io/io/inc/TBufferFile.h +++ b/io/io/inc/TBufferFile.h @@ -112,7 +112,7 @@ class TBufferFile : public TBufferIO { char *ReadString(char *s, Long64_t max) override; void WriteString(const char *s) override; - TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) override; + TClass *ReadClass(const TClass *cl = nullptr, ULong64_t *objTag = nullptr) override; void WriteClass(const TClass *cl) override; TObject *ReadObject(const TClass *cl) override; diff --git a/io/io/inc/TBufferJSON.h b/io/io/inc/TBufferJSON.h index 8ab2d521e6a1d..011b1a7ae8743 100644 --- a/io/io/inc/TBufferJSON.h +++ b/io/io/inc/TBufferJSON.h @@ -99,7 +99,7 @@ class TBufferJSON final : public TBufferText { // suppress class writing/reading - TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) final; + TClass *ReadClass(const TClass *cl = nullptr, ULong64_t *objTag = nullptr) final; void WriteClass(const TClass *cl) final; // redefined virtual functions of TBuffer diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index c1b44274aa692..a837f25df815f 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -2600,7 +2600,7 @@ void *TBufferFile::ReadObjectAny(const TClass *clCast) ULong64_t cntpos = startpos <= kMaxCountPosition ? startpos : kOverflowPosition; // attempt to load next object as TClass clCast - UInt_t tag; // either tag or byte count + ULong64_t tag; // either tag or byte count TClass *clRef = ReadClass(clCast, &tag); TClass *clOnfile = nullptr; Int_t baseOffset = 0; @@ -2808,7 +2808,7 @@ void TBufferFile::WriteObjectClass(const void *actualObjectStart, const TClass * /// \param[in] clReq Can be used to cross check if the actually read object is of the requested class. /// \param[in] objTag Set in case the object is a reference to an already read object. -TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) +TClass *TBufferFile::ReadClass(const TClass *clReq, ULong64_t *objTag) { R__ASSERT(IsReading()); @@ -2852,16 +2852,26 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, UInt_t *objTag) if (R__likely(shortRange)) { UInt_t tag; *this >> tag; + isNewClassTag = (tag == kNewClassTag); tag64 = tag; } else { - *this >> tag64; + UInt_t high32, low32; + *this >> high32; + if (high32 == kNewClassTag) { + isNewClassTag = true; + tag64 = 0; + } else { + // continue reading low 32-bits + *this >> low32; + tag64 = (static_cast(high32) << 32) | low32; + } } } const bool isClassTag = shortRange ? (tag64 & kClassMask) : (tag64 & kLongRangeClassMask); // in case tag is object tag return tag - if (!isClassTag) { + if (!isClassTag && !isNewClassTag) { // FIXME/TRUNCATION: potential truncation from 64 to 32 bits if (objTag) *objTag = tag64; diff --git a/io/io/src/TBufferJSON.cxx b/io/io/src/TBufferJSON.cxx index 23ff6091ea355..e0a297bc3d626 100644 --- a/io/io/src/TBufferJSON.cxx +++ b/io/io/src/TBufferJSON.cxx @@ -2533,7 +2533,7 @@ void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_ //////////////////////////////////////////////////////////////////////////////// /// suppressed function of TBuffer -TClass *TBufferJSON::ReadClass(const TClass *, UInt_t *) +TClass *TBufferJSON::ReadClass(const TClass *, ULong64_t *) { return nullptr; } diff --git a/io/io/src/TContainerConverters.cxx b/io/io/src/TContainerConverters.cxx index c5f8fe65c4a5f..ff464ba3227c8 100644 --- a/io/io/src/TContainerConverters.cxx +++ b/io/io/src/TContainerConverters.cxx @@ -105,7 +105,7 @@ void TConvertClonesArrayToProxy::operator()(TBuffer &b, void *pmember, Int_t siz UInt_t startpos = b.Length(); // attempt to load next object as TClass clCast - UInt_t tag; // either tag or byte count + ULong64_t tag; // either tag or byte count TClass *clRef = b.ReadClass(TClonesArray::Class(), &tag); if (clRef==0) { @@ -122,7 +122,7 @@ void TConvertClonesArrayToProxy::operator()(TBuffer &b, void *pmember, Int_t siz b.GetMappedObject( tag, objptr, clRef); if ( objptr == (void*)-1 ) { Error("TConvertClonesArrayToProxy", - "Object can not be found in the buffer's map (at %d)",tag); + "Object can not be found in the buffer's map (at %llu)", tag); continue; } if ( objptr == 0 ) { diff --git a/io/sql/inc/TBufferSQL2.h b/io/sql/inc/TBufferSQL2.h index 1c7c7e696adae..4f7fc0af223ba 100644 --- a/io/sql/inc/TBufferSQL2.h +++ b/io/sql/inc/TBufferSQL2.h @@ -139,7 +139,7 @@ class TBufferSQL2 final : public TBufferText { // suppress class writing/reading - TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) final; + TClass *ReadClass(const TClass *cl = nullptr, ULong64_t *objTag = nullptr) final; void WriteClass(const TClass *cl) final; // redefined virtual functions of TBuffer diff --git a/io/sql/src/TBufferSQL2.cxx b/io/sql/src/TBufferSQL2.cxx index cf43d319f9a73..6e7556c7a6be4 100644 --- a/io/sql/src/TBufferSQL2.cxx +++ b/io/sql/src/TBufferSQL2.cxx @@ -784,7 +784,7 @@ void TBufferSQL2::WorkWithElement(TStreamerElement *elem, Int_t /* comp_type */) //////////////////////////////////////////////////////////////////////////////// /// Suppressed function of TBuffer -TClass *TBufferSQL2::ReadClass(const TClass *, UInt_t *) +TClass *TBufferSQL2::ReadClass(const TClass *, ULong64_t *) { return nullptr; } diff --git a/io/xml/inc/TBufferXML.h b/io/xml/inc/TBufferXML.h index 4210e1eb159dc..ace668dfa4ef7 100644 --- a/io/xml/inc/TBufferXML.h +++ b/io/xml/inc/TBufferXML.h @@ -67,7 +67,7 @@ class TBufferXML final : public TBufferText, public TXMLSetup { // suppress class writing/reading - TClass *ReadClass(const TClass *cl = nullptr, UInt_t *objTag = nullptr) final; + TClass *ReadClass(const TClass *cl = nullptr, ULong64_t *objTag = nullptr) final; void WriteClass(const TClass *cl) final; // redefined virtual functions of TBuffer diff --git a/io/xml/src/TBufferXML.cxx b/io/xml/src/TBufferXML.cxx index 8e4330dd11c0e..37cd0424123c4 100644 --- a/io/xml/src/TBufferXML.cxx +++ b/io/xml/src/TBufferXML.cxx @@ -1400,7 +1400,7 @@ void TBufferXML::BeforeIOoperation() //////////////////////////////////////////////////////////////////////////////// /// Function to read class from buffer, used in old-style streamers -TClass *TBufferXML::ReadClass(const TClass *, UInt_t *) +TClass *TBufferXML::ReadClass(const TClass *, ULong64_t *) { const char *clname = nullptr; From 9bfe65ffb7300ffd16a90cdb6f897df86320bd0b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Tue, 16 Dec 2025 11:05:07 -0600 Subject: [PATCH 21/22] io: Properly handle nullptr in longRange section. Reference in the longRange section (>1GB) are now tagged so that we can differentiate nullptr (stored as only 32 bits) from short reference stored in the longRange section (i.e. those are stored in 64 bits but have only zeros in the high bit). --- io/io/src/TBufferFile.cxx | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/io/io/src/TBufferFile.cxx b/io/io/src/TBufferFile.cxx index a837f25df815f..37c0637da15d6 100644 --- a/io/io/src/TBufferFile.cxx +++ b/io/io/src/TBufferFile.cxx @@ -74,9 +74,10 @@ constexpr Version_t kByteCountVMask = 0x4000; // OR the version byte coun constexpr Version_t kMaxVersion = 0x3FFF; // highest possible version number constexpr Int_t kMapOffset = 2; // first 2 map entries are taken by null obj and self obj -// constexpr ULong64_t kMaxLongRange = 0x0FFFFFFFFFFFFFFE; // We reserve the 4 highest bits for flags, currently only 2 are in use. +constexpr ULong64_t kMaxLongRange = 0x0FFFFFFFFFFFFFFE; // We reserve the 4 highest bits for flags, currently only 2 are in use. constexpr ULong64_t kLongRangeClassMask = 0x8000000000000000; // OR the class index with this // constexpr ULong64_t kLongRangeByteCountMask = 0x4000000000000000; // OR the byte count with this +constexpr ULong64_t kLongRangeRefMask = 0x2000000000000000; // OR the reference index with this //////////////////////////////////////////////////////////////////////////////// /// Thread-safe check on StreamerInfos of a TClass @@ -2750,14 +2751,25 @@ void TBufferFile::WriteObjectClass(const void *actualObjectStart, const TClass * ULong_t hash = Void_Hash(actualObjectStart); if ((idx = (ULongptr_t)fMap->GetValue(hash, (Longptr_t)actualObjectStart, slot)) != 0) { - - // truncation is OK the value we did put in the map is an 30-bit offset - // and not a pointer - UInt_t objIdx = UInt_t(idx); + const bool shortRange = (fBufCur - fBuffer) <= kMaxMapCount; // save index of already stored object // FIXME/TRUNCATION: potential truncation from 64 to 32 bits - *this << objIdx; + if (R__likely(shortRange)) { + // truncation is OK the value we did put in the map is an 30-bit offset + // and not a pointer + UInt_t objIdx = UInt_t(idx); + *this << objIdx; + } else { + // The 64-bit value is stored highest bytes first in the buffer, + // so when reading just the first 32-bits we get the control bits in place. + // This is needed so that the reader can distinguish between references, + // bytecounts, and new class definitions. + ULong64_t objIdx = static_cast(idx); + // FIXME: verify that objIdx is guaranteed to fit in 60-bits, i.e. objIdx <= kMaxLongRange + assert(objIdx <= kMaxLongRange); + *this << (objIdx | kLongRangeRefMask); + } } else { @@ -2833,13 +2845,17 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, ULong64_t *objTag) } else if (!(bcnt & kByteCountMask)) { if (R__likely(shortRange)) { tag64 = bcnt; - } else { + } else if (bcnt & ((kLongRangeRefMask|kLongRangeClassMask) >> 32)) { // Two implementation choices: // 1) rewind and read full 64-bit value // 2) use the already read 32-bits, read the rest and combine UInt_t low32; *this >> low32; tag64 = (static_cast(bcnt) << 32) | low32; + tag64 &= ~kLongRangeRefMask; + } else { + R__ASSERT(bcnt == 0); // isn't it? If true we could return 0 early with (*objTag=0) + tag64 = bcnt; } bcnt = 0; } else { @@ -2860,10 +2876,14 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, ULong64_t *objTag) if (high32 == kNewClassTag) { isNewClassTag = true; tag64 = 0; - } else { + } else if (high32 & ((kLongRangeRefMask|kLongRangeClassMask) >> 32)) { // continue reading low 32-bits *this >> low32; tag64 = (static_cast(high32) << 32) | low32; + tag64 &= ~kLongRangeRefMask; + } else { + R__ASSERT(high32 == 0); // isn't it? If true we could return 0 early with (*objTag=0) + tag64 = high32; } } } @@ -2871,6 +2891,7 @@ TClass *TBufferFile::ReadClass(const TClass *clReq, ULong64_t *objTag) const bool isClassTag = shortRange ? (tag64 & kClassMask) : (tag64 & kLongRangeClassMask); // in case tag is object tag return tag + // NOTE: if we return early for reference for longRange, this would be only for shortRange if (!isClassTag && !isNewClassTag) { // FIXME/TRUNCATION: potential truncation from 64 to 32 bits if (objTag) @@ -2964,6 +2985,8 @@ void TBufferFile::WriteClass(const TClass *cl) // This is needed so that the reader can distinguish between references, // bytecounts, and new class definitions. ULong64_t clIdx = static_cast(idx); + // FIXME: verify that clIdx is guaranteed to fit in 60-bits, i.e. clIdx <= kMaxLongRange + assert(clIdx <= kMaxLongRange); *this << (clIdx | kLongRangeClassMask); } } else { From 52b3714a23cd56f39d75d45de01320e32474338b Mon Sep 17 00:00:00 2001 From: Philippe Canal Date: Wed, 4 Feb 2026 19:27:25 +0100 Subject: [PATCH 22/22] io: Enable long range reference test --- io/io/test/InnerReferencesTests.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io/io/test/InnerReferencesTests.cxx b/io/io/test/InnerReferencesTests.cxx index eef112d289e92..6b2dd248bec07 100644 --- a/io/io/test/InnerReferencesTests.cxx +++ b/io/io/test/InnerReferencesTests.cxx @@ -122,7 +122,7 @@ TEST(TBufferFileInnerReferences, LargeOffsetsAndReferences) errors += ReadAndCheck(b, n0->IsA(), rn0.get()).fError; errors += ReadAndCheck(b, n1->IsA(), rn1.get()).fError; errors += ReadAndCheck(b, m1->IsA(), rm1.get()).fError; - if (0) { // These require implementing proper support for long range references. + if (1) { // These require implementing proper support for long range references. errors += ReadAndCheck(b, n2->IsA(), rn2.get()).fError; // Reference over 1G errors += ReadAndCheck(b, m2->IsA(), rm2.get()).fError; // Reference over 1G errors += ReadAndCheck(b, c1->IsA(), rc1.get()).fError; // Class and reference over 1G