Skip to content

Commit aa52b32

Browse files
committed
[io] Introduce safer overload of TKey::ReadKeyBuffer
1 parent c5e8408 commit aa52b32

2 files changed

Lines changed: 124 additions & 0 deletions

File tree

io/io/inc/TKey.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class TKey : public TNamed {
108108
virtual void *ReadObjectAny(const TClass *expectedClass);
109109
virtual void ReadBuffer(char *&buffer);
110110
void ReadKeyBuffer(char *&buffer);
111+
void ReadKeyBuffer(char *&buffer, std::size_t bufsize);
111112
virtual Bool_t ReadFile();
112113
virtual void SetBuffer() { DeleteBuffer(); fBuffer = new char[fNbytes];}
113114
virtual void SetParent(const TObject *parent);

io/io/src/TKey.cxx

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,129 @@ void TKey::ReadKeyBuffer(char *&buffer)
12841284
fTitle.ReadBuffer(buffer);
12851285
}
12861286

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

0 commit comments

Comments
 (0)