Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/base/inc/TString.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ friend std::strong_ordering operator<=>(const TString &s1, const TString &s2) {
virtual void ReadBuffer(char *&buffer);
virtual Int_t Sizeof() const;

[[nodiscard]] std::size_t ReadBuffer(const char *buffer, std::size_t bufsize);

static TString *ReadString(TBuffer &b, const TClass *clReq);
static void WriteString(TBuffer &b, const TString *a);

Expand Down
67 changes: 66 additions & 1 deletion core/base/src/TString.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1355,7 +1355,72 @@ void TString::ReadBuffer(char *&buffer)

char *data = Init(nchars, nchars);

for (int i = 0; i < nchars; i++) frombuf(buffer, &data[i]);
memcpy(data, buffer, nchars);
buffer += nchars;
}

////////////////////////////////////////////////////////////////////////////////
/// Safer version of ReadBuffer(char *&buffer), doing bound checks on the given buffer.
/// This overload should be preferred over the other, which should be considered unsafe.
/// Note that, unlike the unsafe overload, this method does not advance the input buffer!
/// \return The amount of bytes read from the buffer, or 0 in case of errors.

std::size_t TString::ReadBuffer(const char *buffer, std::size_t bufsize)
{
// NOTE: this is not a lambda because we want [[nodiscard]].
struct {
TString *fOuter;
std::size_t fRemainingBufSize;

[[nodiscard]] bool operator()(std::size_t additionalBytesNeeded)
{
if (R__unlikely(additionalBytesNeeded > fRemainingBufSize)) {
Error("TString::ReadBuffer", "given buffer is too small (%zu B remaining, need at least %zu more)",
fRemainingBufSize, additionalBytesNeeded);
fOuter->UnLink();
fOuter->Zero();
return false;
}
fRemainingBufSize -= additionalBytesNeeded;
return true;
}
} RequireAdditionalBufCapacity{this, bufsize};

if (!RequireAdditionalBufCapacity(1)) {
return 0;
}

UnLink();
Zero();

UChar_t strLength;
Int_t nchars;

// frombuf needs a non-const buffer, although it actually doesn't modify it.
char *buf = const_cast<char *>(buffer);
frombuf(buf, &strLength);
if (strLength == 255) {
if (!RequireAdditionalBufCapacity(sizeof(nchars))) {
return 0;
}
frombuf(buf, &nchars);
} else {
nchars = strLength;
}

if (nchars < 0) {
Error("TString::ReadBuffer", "found case with nwh=%d and nchars=%d", strLength, nchars);
return 0;
}

char *data = Init(nchars, nchars);

if (!RequireAdditionalBufCapacity(nchars)) {
return 0;
}
memcpy(data, buf, nchars);

return bufsize - RequireAdditionalBufCapacity.fRemainingBufSize;
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions io/io/inc/TKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class TKey : public TNamed {
virtual void *ReadObjectAny(const TClass *expectedClass);
virtual void ReadBuffer(char *&buffer);
void ReadKeyBuffer(char *&buffer);
void ReadKeyBuffer(char *&buffer, std::size_t bufsize);
virtual Bool_t ReadFile();
virtual void SetBuffer() { DeleteBuffer(); fBuffer = new char[fNbytes];}
virtual void SetParent(const TObject *parent);
Expand Down
41 changes: 21 additions & 20 deletions io/io/src/TFile.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -2100,13 +2100,6 @@ TProcessID *TFile::ReadProcessID(UShort_t pidf)

Int_t TFile::Recover()
{
Short_t keylen,cycle;
UInt_t datime;
Int_t nbytes,date,time,objlen,nwheader;
Long64_t seekkey,seekpdir;
char header[1024];
char *buffer, *bufread;
char nwhc;
Long64_t idcur = fBEGIN;

Long64_t size;
Expand All @@ -2120,10 +2113,11 @@ Int_t TFile::Recover()
if (fWritable && !fFree) fFree = new TList;

Int_t nrecov = 0;
nwheader = 1024;
Int_t nread = nwheader;

while (idcur < fEND) {
char header[1024];
int nread = sizeof(header);

Seek(idcur); // NOLINT: silence clang-tidy warnings
if (idcur+nread >= fEND) nread = fEND-idcur-1;
if (ReadBuffer(header, nread)) { // NOLINT: silence clang-tidy warnings
Expand All @@ -2132,8 +2126,8 @@ Int_t TFile::Recover()
GetName(),idcur);
break;
}
buffer = header;
bufread = header;
char *buffer = header;
Int_t nbytes;
frombuf(buffer, &nbytes);
if (!nbytes) {
Error("Recover","Address = %lld\tNbytes = %d\t=====E R R O R=======", idcur, nbytes);
Expand All @@ -2147,10 +2141,15 @@ Int_t TFile::Recover()
}
Version_t versionkey;
frombuf(buffer, &versionkey);
Int_t objlen;
frombuf(buffer, &objlen);
UInt_t datime;
frombuf(buffer, &datime);
Short_t keylen;
frombuf(buffer, &keylen);
Short_t cycle;
frombuf(buffer, &cycle);
Long64_t seekkey, seekpdir;
if (versionkey > 1000) {
frombuf(buffer, &seekkey);
frombuf(buffer, &seekpdir);
Expand All @@ -2159,19 +2158,22 @@ Int_t TFile::Recover()
frombuf(buffer, &skey); seekkey = (Long64_t)skey;
frombuf(buffer, &sdir); seekpdir = (Long64_t)sdir;
}
frombuf(buffer, &nwhc);
char *classname = nullptr;
if (nwhc <= 0 || nwhc > 100) break;
classname = new char[nwhc+1];
int i, nwhci = nwhc;
for (i = 0;i < nwhc; i++) frombuf(buffer, &classname[i]);
classname[nwhci] = '\0';
char classnameLen;
frombuf(buffer, &classnameLen);
char classname[101];
if (classnameLen <= 0 || classnameLen > (Int_t)sizeof(classname))
break;
memcpy(classname, buffer, classnameLen);
buffer += classnameLen;
classname[static_cast<std::size_t>(classnameLen)] = '\0';
Int_t date, time;
TDatime::GetDateTime(datime, date, time);
TClass *tclass = TClass::GetClass(classname);
if (seekpdir == fSeekDir && tclass && !tclass->InheritsFrom(TFile::Class())
&& strcmp(classname,"TBasket")) {
TKey *key = new TKey(this);
key->ReadKeyBuffer(bufread);
char *bufread = header;
key->ReadKeyBuffer(bufread, sizeof(header));
if (!strcmp(key->GetName(),"StreamerInfo")) {
fSeekInfo = seekkey;
SafeDelete(fInfoCache);
Expand All @@ -2184,7 +2186,6 @@ Int_t TFile::Recover()
Info("Recover", "%s, recovered key %s:%s at address %lld",GetName(),key->GetClassName(),key->GetName(),idcur);
}
}
delete [] classname;
idcur += nbytes;
}
if (fWritable) {
Expand Down
123 changes: 123 additions & 0 deletions io/io/src/TKey.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,129 @@ void TKey::ReadKeyBuffer(char *&buffer)
fTitle.ReadBuffer(buffer);
}

void TKey::ReadKeyBuffer(char *&buffer, std::size_t bufsize)
{
// NOTE: this is not a lambda because we want [[nodiscard]].
struct {
TKey *fOuter;
std::size_t fRemainingBufSize;
[[nodiscard]] bool operator()(std::size_t additionalBytesNeeded) {
if (R__unlikely(additionalBytesNeeded > fRemainingBufSize)) {
fOuter->Error("ReadKeyBuffer", "The given buffer is too small to fit this TKey.");
fOuter->MakeZombie();
return false;
}
fRemainingBufSize -= additionalBytesNeeded;
return true;
}
} RequireAdditionalBufCapacity{this, bufsize};

// Min size of the buffer for reading the common key header data
constexpr std::size_t kMinBufSize =
sizeof(fNbytes) + sizeof(Version_t) + sizeof(fObjlen) + sizeof(fKeylen) + sizeof(fCycle);
if (!RequireAdditionalBufCapacity(kMinBufSize))
return;

frombuf(buffer, &fNbytes);
if (fNbytes < 0) {
Error("ReadKeyBuffer", "The value of fNbytes is negative (%d): cannot continue to read the key buffer.", fNbytes);
MakeZombie();
fNbytes = 0;
return;
}
Version_t version;
frombuf(buffer,&version);
fVersion = (Int_t)version;
frombuf(buffer, &fObjlen);
if (fObjlen < 0) {
Error("ReadKeyBuffer", "The value of fObjlen is negative (%d): cannot continue to read the key buffer.", fObjlen);
MakeZombie();
fObjlen = 0;
return;
}
fDatime.ReadBuffer(buffer);
frombuf(buffer, &fKeylen);
if (fKeylen < 0) {
Error("ReadKeyBuffer", "The value of fKeylen is negative (%d): cannot continue to read the key buffer.", fKeylen);
MakeZombie();
fKeylen = 0;
return;
}

if (fNbytes < fKeylen) {
Error("ReadKeyBuffer", "fNbytes (%d) < fKeylen (%d): cannot continue to read the key buffer.", fNbytes, fKeylen);
MakeZombie();
return;
}

constexpr auto maxInt_t = std::numeric_limits<Int_t>::max();
if (fKeylen > (maxInt_t - fObjlen)) {
Error("ReadKeyBuffer", "fObjlen (%d) + fKeylen (%d) > max int (%d): cannot continue to read the key buffer.", fObjlen, fKeylen, maxInt_t);
MakeZombie();
return;
}

frombuf(buffer, &fCycle);
// The initial bufsize check guarantees that we could read up to here.
// From now on we need to be careful.

if (fVersion > 1000) {
if (!RequireAdditionalBufCapacity(sizeof(fSeekKey) + sizeof(Long64_t)))
return;

frombuf(buffer, &fSeekKey);

// We currently store in the 16 highest bit of fSeekPdir the value of
// fPidOffset. This offset is used when a key (or basket) is transferred from one
// file to the other. In this case the TRef and TObject might have stored a
// pid index (to retrieve TProcessIDs) which refered to their order on the original
// file, the fPidOffset is to be added to those values to correctly find the
// TProcessID. This fPidOffset needs to be increment if the key/basket is copied
// and need to be zero for new key/basket.
Long64_t pdir;
frombuf(buffer, &pdir);
fPidOffset = pdir >> kPidOffsetShift;
fSeekPdir = pdir & kPidOffsetMask;
} else {
if (!RequireAdditionalBufCapacity(2 * sizeof(UInt_t)))
return;

UInt_t seekkey,seekdir;
frombuf(buffer, &seekkey);
fSeekKey = (Long64_t)seekkey;
frombuf(buffer, &seekdir);
fSeekPdir = (Long64_t)seekdir;
}

auto nRead = fClassName.ReadBuffer(buffer, RequireAdditionalBufCapacity.fRemainingBufSize);
if (!nRead) {
MakeZombie();
return;
}
buffer += nRead;
RequireAdditionalBufCapacity.fRemainingBufSize -= nRead;

//the following test required for forward and backward compatibility
if (fClassName == "TDirectory") {
fClassName = "TDirectoryFile";
SetBit(kIsDirectoryFile);
}

nRead = fName.ReadBuffer(buffer, RequireAdditionalBufCapacity.fRemainingBufSize);
if (!nRead) {
MakeZombie();
return;
}
buffer += nRead;
RequireAdditionalBufCapacity.fRemainingBufSize -= nRead;

nRead = fTitle.ReadBuffer(buffer, RequireAdditionalBufCapacity.fRemainingBufSize);
if (!nRead) {
MakeZombie();
}
buffer += nRead;
}

////////////////////////////////////////////////////////////////////////////////
/// Read the key structure from the file

Expand Down
Loading