Skip to content

Commit 415e577

Browse files
committed
[core] Introduce safer overload of TString::ReadBuffer
1 parent ae81825 commit 415e577

2 files changed

Lines changed: 69 additions & 1 deletion

File tree

core/base/inc/TString.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ friend std::strong_ordering operator<=>(const TString &s1, const TString &s2) {
305305
virtual void ReadBuffer(char *&buffer);
306306
virtual Int_t Sizeof() const;
307307

308+
std::size_t ReadBuffer(char *&buffer, std::size_t bufsize);
309+
308310
static TString *ReadString(TBuffer &b, const TClass *clReq);
309311
static void WriteString(TBuffer &b, const TString *a);
310312

core/base/src/TString.cxx

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,73 @@ void TString::ReadBuffer(char *&buffer)
13551355

13561356
char *data = Init(nchars, nchars);
13571357

1358-
for (int i = 0; i < nchars; i++) frombuf(buffer, &data[i]);
1358+
memcpy(data, buffer, nchars);
1359+
buffer += nchars;
1360+
}
1361+
1362+
////////////////////////////////////////////////////////////////////////////////
1363+
/// Safer version of ReadBuffer(char *&buffer), doing bound checks on the given buffer.
1364+
/// This overload should be preferred over the other, which should be considered unsafe.
1365+
/// \return The amount of bytes read from the buffer, or 0 in case of errors.
1366+
1367+
std::size_t TString::ReadBuffer(char *&buffer, std::size_t bufsize)
1368+
{
1369+
// NOTE: this is not a lambda because we want [[nodiscard]].
1370+
struct {
1371+
TString *fOuter;
1372+
std::size_t fRemainingBufSize;
1373+
1374+
[[nodiscard]] bool operator()(std::size_t additionalBytesNeeded)
1375+
{
1376+
if (R__unlikely(additionalBytesNeeded > fRemainingBufSize)) {
1377+
Error("TString::ReadBuffer", "given buffer is too small (%zu B remaining, need at least %zu more)",
1378+
fRemainingBufSize, additionalBytesNeeded);
1379+
fOuter->UnLink();
1380+
fOuter->Zero();
1381+
return false;
1382+
}
1383+
fRemainingBufSize -= additionalBytesNeeded;
1384+
return true;
1385+
}
1386+
} ConsumeBufCapacity{this, bufsize};
1387+
1388+
if (!ConsumeBufCapacity(1)) {
1389+
return 0;
1390+
}
1391+
1392+
UnLink();
1393+
Zero();
1394+
1395+
UChar_t strLength;
1396+
Int_t nchars;
1397+
1398+
// frombuf needs a non-const buffer, although it actually doesn't modify it.
1399+
char *buf = const_cast<char *>(buffer);
1400+
frombuf(buf, &strLength);
1401+
if (strLength == 255) {
1402+
if (!ConsumeBufCapacity(sizeof(nchars))) {
1403+
return 0;
1404+
}
1405+
frombuf(buf, &nchars);
1406+
} else {
1407+
nchars = strLength;
1408+
}
1409+
1410+
if (nchars < 0) {
1411+
Error("TString::ReadBuffer", "found case with nwh=%d and nchars=%d", strLength, nchars);
1412+
return 0;
1413+
}
1414+
1415+
char *data = Init(nchars, nchars);
1416+
1417+
if (!ConsumeBufCapacity(nchars)) {
1418+
return 0;
1419+
}
1420+
memcpy(data, buf, nchars);
1421+
1422+
std::size_t nbytesRead = bufsize - ConsumeBufCapacity.fRemainingBufSize;
1423+
buffer += nbytesRead;
1424+
return nbytesRead;
13591425
}
13601426

13611427
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)