Skip to content

Commit d7f410b

Browse files
authored
[core] prevent integer overflow when calling Align
1 parent 3e9bbe4 commit d7f410b

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

core/base/inc/TString.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,16 @@ friend std::strong_ordering operator<=>(const TString &s1, const TString &s2) {
230230

231231
enum { kAlignment = 16 };
232232
static Ssiz_t Align(Ssiz_t s) { return (s + (kAlignment-1)) & ~(kAlignment-1); }
233-
static Ssiz_t Recommend(Ssiz_t s) { return (s < kMinCap ? kMinCap : Align(s+1)) - 1; }
233+
// `s` is expected to be <= MaxSize() = (kMaxInt-1) ; `s + 1` includes the terminating nullchar
234+
static Ssiz_t Recommend(Ssiz_t s)
235+
{
236+
if (s < kMinCap)
237+
return kMinCap;
238+
else if (s > MaxSize() - (kAlignment - 1))
239+
return s;
240+
else
241+
return Align(s + 1) - 1;
242+
}
234243
static Ssiz_t AdjustCapacity(Ssiz_t oldCap, Ssiz_t newCap);
235244

236245
private:
@@ -255,9 +264,9 @@ friend std::strong_ordering operator<=>(const TString &s1, const TString &s2) {
255264
char *GetPointer() { return IsLong() ? GetLongPointer() : GetShortPointer(); }
256265
const char *GetPointer() const { return IsLong() ? GetLongPointer() : GetShortPointer(); }
257266
#ifdef R__BYTESWAP
258-
static Ssiz_t MaxSize() { return kMaxInt - 1; }
267+
static constexpr Ssiz_t MaxSize() { return kMaxInt - 1; }
259268
#else
260-
static Ssiz_t MaxSize() { return (kMaxInt >> 1) - 1; }
269+
static constexpr Ssiz_t MaxSize() { return (kMaxInt >> 1) - 1; }
261270
#endif
262271
void UnLink() const { if (IsLong()) delete [] fRep.fLong.fData; }
263272
void Zero() {

core/base/src/TString.cxx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ strings (<15 on 64-bit and <11 on 32-bit) are contained in the
2323
TString internal data structure without the need for mallocing the
2424
required space.
2525
26+
\note TString can store a maximum of MaxSize()=2147483646 characters; ie 2147483647 bytes if you include the terminating null.
27+
Trying to allocate larger buffers might throw std::bad_alloc or raise
28+
Fatal errors or lead to undefined behavior. Likewise, there is no safety
29+
check if you pass a Long64_t to the class functions, they will be silently
30+
rounded to Int_t and lead to an integer overflow (negative value).
31+
For future designs, consider using std::string instead, which has a larger
32+
maximum size.
33+
2634
Substring operations are provided by the TSubString class, which
2735
holds a reference to the original string and its data, along with
2836
the offset and length of the substring. To retrieve the substring
@@ -1220,12 +1228,11 @@ void TString::AssertElement(Ssiz_t i) const
12201228
Ssiz_t TString::AdjustCapacity(Ssiz_t oldCap, Ssiz_t newCap)
12211229
{
12221230
Ssiz_t ms = MaxSize();
1223-
if (newCap > ms - 1) {
1231+
if (newCap > ms) {
12241232
Fatal("TString::AdjustCapacity", "capacity too large (%d, max = %d)",
12251233
newCap, ms);
12261234
}
1227-
Ssiz_t cap = oldCap < ms / 2 - kAlignment ?
1228-
Recommend(std::max(newCap, 2 * oldCap)) : ms - 1;
1235+
Ssiz_t cap = oldCap <= ms / 2 ? Recommend(std::max(newCap, 2 * oldCap)) : ms;
12291236
return cap;
12301237
}
12311238

0 commit comments

Comments
 (0)