Skip to content

Commit 8693edf

Browse files
committed
[io] Introduce safer overload of TKey::ReadKeyBuffer
1 parent 415e577 commit 8693edf

2 files changed

Lines changed: 128 additions & 1 deletion

File tree

io/io/inc/TKey.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ class TKey : public TNamed {
108108
virtual void *ReadObjectAny(const TClass *expectedClass);
109109
virtual void ReadBuffer(char *&buffer);
110110
void ReadKeyBuffer(char *&buffer);
111+
bool ReadKeyBuffer(char *&buffer, std::size_t bufsize);
111112
virtual Bool_t ReadFile();
112-
virtual void SetBuffer() { DeleteBuffer(); fBuffer = new char[fNbytes];}
113+
virtual void SetBuffer() { DeleteBuffer(); fBuffer = new char[fNbytes]; }
113114
virtual void SetParent(const TObject *parent);
114115
void SetMotherDir(TDirectory* dir) { fMotherDir = dir; }
115116
Int_t Sizeof() const override;

io/io/src/TKey.cxx

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,132 @@ void TKey::ReadKeyBuffer(char *&buffer)
12961296
fTitle.ReadBuffer(buffer);
12971297
}
12981298

1299+
////////////////////////////////////////////////////////////////////////////////
1300+
/// Decode input buffer.
1301+
/// \return true if decoding was successful.
1302+
1303+
bool TKey::ReadKeyBuffer(char *&buffer, std::size_t bufsize)
1304+
{
1305+
// NOTE: this is not a lambda because we want [[nodiscard]].
1306+
struct {
1307+
TKey *fOuter;
1308+
std::size_t fRemainingBufSize;
1309+
[[nodiscard]] bool operator()(std::size_t additionalBytesNeeded) {
1310+
if (R__unlikely(additionalBytesNeeded > fRemainingBufSize)) {
1311+
fOuter->Error("ReadKeyBuffer", "The given buffer is too small to fit this TKey.");
1312+
fOuter->MakeZombie();
1313+
return false;
1314+
}
1315+
fRemainingBufSize -= additionalBytesNeeded;
1316+
return true;
1317+
}
1318+
} ConsumeBufCapacity{this, bufsize};
1319+
1320+
// Min size of the buffer for reading the common key header data
1321+
constexpr std::size_t kMinBufSize =
1322+
sizeof(fNbytes) + sizeof(Version_t) + sizeof(fObjlen) + sizeof(fKeylen) + sizeof(fCycle);
1323+
if (!ConsumeBufCapacity(kMinBufSize))
1324+
return false;
1325+
1326+
frombuf(buffer, &fNbytes);
1327+
if (fNbytes < 0) {
1328+
Error("ReadKeyBuffer", "The value of fNbytes is negative (%d): cannot continue to read the key buffer.", fNbytes);
1329+
MakeZombie();
1330+
fNbytes = 0;
1331+
return false;
1332+
}
1333+
Version_t version;
1334+
frombuf(buffer,&version);
1335+
fVersion = (Int_t)version;
1336+
frombuf(buffer, &fObjlen);
1337+
if (fObjlen < 0) {
1338+
Error("ReadKeyBuffer", "The value of fObjlen is negative (%d): cannot continue to read the key buffer.", fObjlen);
1339+
MakeZombie();
1340+
fObjlen = 0;
1341+
return false;
1342+
}
1343+
fDatime.ReadBuffer(buffer);
1344+
frombuf(buffer, &fKeylen);
1345+
if (fKeylen < 0) {
1346+
Error("ReadKeyBuffer", "The value of fKeylen is negative (%d): cannot continue to read the key buffer.", fKeylen);
1347+
MakeZombie();
1348+
fKeylen = 0;
1349+
return false;
1350+
}
1351+
1352+
if (fNbytes < fKeylen) {
1353+
Error("ReadKeyBuffer", "fNbytes (%d) < fKeylen (%d): cannot continue to read the key buffer.", fNbytes, fKeylen);
1354+
MakeZombie();
1355+
return false;
1356+
}
1357+
1358+
constexpr auto maxInt_t = std::numeric_limits<Int_t>::max();
1359+
if (fKeylen > (maxInt_t - fObjlen)) {
1360+
Error("ReadKeyBuffer", "fObjlen (%d) + fKeylen (%d) > max int (%d): cannot continue to read the key buffer.", fObjlen, fKeylen, maxInt_t);
1361+
MakeZombie();
1362+
return false;
1363+
}
1364+
1365+
frombuf(buffer, &fCycle);
1366+
// The initial bufsize check guarantees that we could read up to here.
1367+
// From now on we need to be careful.
1368+
1369+
if (fVersion > 1000) {
1370+
if (!ConsumeBufCapacity(sizeof(fSeekKey) + sizeof(Long64_t)))
1371+
return false;
1372+
1373+
frombuf(buffer, &fSeekKey);
1374+
1375+
// We currently store in the 16 highest bit of fSeekPdir the value of
1376+
// fPidOffset. This offset is used when a key (or basket) is transferred from one
1377+
// file to the other. In this case the TRef and TObject might have stored a
1378+
// pid index (to retrieve TProcessIDs) which refered to their order on the original
1379+
// file, the fPidOffset is to be added to those values to correctly find the
1380+
// TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1381+
// and need to be zero for new key/basket.
1382+
Long64_t pdir;
1383+
frombuf(buffer, &pdir);
1384+
fPidOffset = pdir >> kPidOffsetShift;
1385+
fSeekPdir = pdir & kPidOffsetMask;
1386+
} else {
1387+
if (!ConsumeBufCapacity(2 * sizeof(UInt_t)))
1388+
return false;
1389+
1390+
UInt_t seekkey,seekdir;
1391+
frombuf(buffer, &seekkey);
1392+
fSeekKey = (Long64_t)seekkey;
1393+
frombuf(buffer, &seekdir);
1394+
fSeekPdir = (Long64_t)seekdir;
1395+
}
1396+
1397+
auto nRead = fClassName.ReadBuffer(buffer, ConsumeBufCapacity.fRemainingBufSize);
1398+
if (!nRead) {
1399+
MakeZombie();
1400+
return false;
1401+
}
1402+
ConsumeBufCapacity.fRemainingBufSize -= nRead;
1403+
1404+
//the following test required for forward and backward compatibility
1405+
if (fClassName == "TDirectory") {
1406+
fClassName = "TDirectoryFile";
1407+
SetBit(kIsDirectoryFile);
1408+
}
1409+
1410+
nRead = fName.ReadBuffer(buffer, ConsumeBufCapacity.fRemainingBufSize);
1411+
if (!nRead) {
1412+
MakeZombie();
1413+
return false;
1414+
}
1415+
ConsumeBufCapacity.fRemainingBufSize -= nRead;
1416+
1417+
nRead = fTitle.ReadBuffer(buffer, ConsumeBufCapacity.fRemainingBufSize);
1418+
if (!nRead) {
1419+
MakeZombie();
1420+
return false;
1421+
}
1422+
return true;
1423+
}
1424+
12991425
////////////////////////////////////////////////////////////////////////////////
13001426
/// Read the key structure from the file
13011427

0 commit comments

Comments
 (0)