Skip to content

Commit eb3ab0d

Browse files
committed
Make DynArray support objects larger than 1 gigabyte
The expression ``const int newAllocated = cap * 2;`` easily causes overflow, as soon as the input is 1.0 GiB. This goes unnoticed because release builds of tinyxml2 do not have active assertions. The change in commit 9.0.0-20-g8fd6cc6 did not do anything useful; the signed multiplication overflow (and thus undefined behavior) still occurs. Using ``int`` in this class is really archaic, because it limits the class to a gigabyte even on 64-bit platforms. The multiplication overflow check also needs to include sizeof(T), otherwise you can run into unsigned multiplication overflow (defined, but undesirable) in the memcpy() call. testcase: int main() { tinyxml2::XMLDocument doc; doc.InsertEndChild(doc.NewDeclaration()); auto root = doc.NewElement("root"); size_t sz = 0x80000001; auto blank = new char[sz]; memset(blank, ' ', sz); blank[sz-1]='\0'; root->SetText(blank); doc.InsertEndChild(root); tinyxml2::XMLPrinter printer(nullptr); doc.Print(&printer); }
1 parent 3a893e5 commit eb3ab0d

2 files changed

Lines changed: 33 additions & 34 deletions

File tree

tinyxml2.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2221,7 +2221,7 @@ void XMLDocument::MarkInUse(const XMLNode* const node)
22212221
TIXMLASSERT(node);
22222222
TIXMLASSERT(node->_parent == 0);
22232223

2224-
for (int i = 0; i < _unlinked.Size(); ++i) {
2224+
for (size_t i = 0; i < _unlinked.Size(); ++i) {
22252225
if (node == _unlinked[i]) {
22262226
_unlinked.SwapRemove(i);
22272227
break;

tinyxml2.h

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ class TINYXML2_LIB StrPair
199199
Has a small initial memory pool, so that low or no usage will not
200200
cause a call to new/delete
201201
*/
202-
template <class T, int INITIAL_SIZE>
202+
template <class T, size_t INITIAL_SIZE>
203203
class DynArray
204204
{
205205
public:
@@ -227,9 +227,8 @@ class DynArray
227227
++_size;
228228
}
229229

230-
T* PushArr( int count ) {
231-
TIXMLASSERT( count >= 0 );
232-
TIXMLASSERT( _size <= INT_MAX - count );
230+
T* PushArr( size_t count ) {
231+
TIXMLASSERT( _size <= SIZE_MAX - count );
233232
EnsureCapacity( _size+count );
234233
T* ret = &_mem[_size];
235234
_size += count;
@@ -242,7 +241,7 @@ class DynArray
242241
return _mem[_size];
243242
}
244243

245-
void PopArr( int count ) {
244+
void PopArr( size_t count ) {
246245
TIXMLASSERT( _size >= count );
247246
_size -= count;
248247
}
@@ -251,13 +250,13 @@ class DynArray
251250
return _size == 0;
252251
}
253252

254-
T& operator[](int i) {
255-
TIXMLASSERT( i>= 0 && i < _size );
253+
T& operator[](size_t i) {
254+
TIXMLASSERT( i < _size );
256255
return _mem[i];
257256
}
258257

259-
const T& operator[](int i) const {
260-
TIXMLASSERT( i>= 0 && i < _size );
258+
const T& operator[](size_t i) const {
259+
TIXMLASSERT( i < _size );
261260
return _mem[i];
262261
}
263262

@@ -266,18 +265,18 @@ class DynArray
266265
return _mem[ _size - 1];
267266
}
268267

269-
int Size() const {
268+
size_t Size() const {
270269
TIXMLASSERT( _size >= 0 );
271270
return _size;
272271
}
273272

274-
int Capacity() const {
273+
size_t Capacity() const {
275274
TIXMLASSERT( _allocated >= INITIAL_SIZE );
276275
return _allocated;
277276
}
278277

279-
void SwapRemove(int i) {
280-
TIXMLASSERT(i >= 0 && i < _size);
278+
void SwapRemove(size_t i) {
279+
TIXMLASSERT(i < _size);
281280
TIXMLASSERT(_size > 0);
282281
_mem[i] = _mem[_size - 1];
283282
--_size;
@@ -297,14 +296,14 @@ class DynArray
297296
DynArray( const DynArray& ); // not supported
298297
void operator=( const DynArray& ); // not supported
299298

300-
void EnsureCapacity( int cap ) {
299+
void EnsureCapacity( size_t cap ) {
301300
TIXMLASSERT( cap > 0 );
302301
if ( cap > _allocated ) {
303-
TIXMLASSERT( cap <= INT_MAX / 2 );
304-
const int newAllocated = cap * 2;
305-
T* newMem = new T[static_cast<unsigned int>(newAllocated)];
302+
TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T));
303+
const size_t newAllocated = cap * 2;
304+
T* newMem = new T[newAllocated];
306305
TIXMLASSERT( newAllocated >= _size );
307-
memcpy( newMem, _mem, sizeof(T)*static_cast<size_t>(_size) ); // warning: not using constructors, only works for PODs
306+
memcpy( newMem, _mem, sizeof(T) * _size ); // warning: not using constructors, only works for PODs
308307
if ( _mem != _pool ) {
309308
delete [] _mem;
310309
}
@@ -314,9 +313,9 @@ class DynArray
314313
}
315314

316315
T* _mem;
317-
T _pool[static_cast<size_t>(INITIAL_SIZE)];
318-
int _allocated; // objects allocated
319-
int _size; // number objects in use
316+
T _pool[INITIAL_SIZE];
317+
size_t _allocated; // objects allocated
318+
size_t _size; // number objects in use
320319
};
321320

322321

@@ -330,7 +329,7 @@ class MemPool
330329
MemPool() {}
331330
virtual ~MemPool() {}
332331

333-
virtual int ItemSize() const = 0;
332+
virtual size_t ItemSize() const = 0;
334333
virtual void* Alloc() = 0;
335334
virtual void Free( void* ) = 0;
336335
virtual void SetTracked() = 0;
@@ -340,7 +339,7 @@ class MemPool
340339
/*
341340
Template child class to create pools of the correct type.
342341
*/
343-
template< int ITEM_SIZE >
342+
template< size_t ITEM_SIZE >
344343
class MemPoolT : public MemPool
345344
{
346345
public:
@@ -362,10 +361,10 @@ class MemPoolT : public MemPool
362361
_nUntracked = 0;
363362
}
364363

365-
virtual int ItemSize() const override{
364+
virtual size_t ItemSize() const override {
366365
return ITEM_SIZE;
367366
}
368-
int CurrentAllocs() const {
367+
size_t CurrentAllocs() const {
369368
return _currentAllocs;
370369
}
371370

@@ -376,7 +375,7 @@ class MemPoolT : public MemPool
376375
_blockPtrs.Push( block );
377376

378377
Item* blockItems = block->items;
379-
for( int i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
378+
for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {
380379
blockItems[i].next = &(blockItems[i + 1]);
381380
}
382381
blockItems[ITEMS_PER_BLOCK - 1].next = 0;
@@ -417,7 +416,7 @@ class MemPoolT : public MemPool
417416
--_nUntracked;
418417
}
419418

420-
int Untracked() const {
419+
size_t Untracked() const {
421420
return _nUntracked;
422421
}
423422

@@ -448,10 +447,10 @@ class MemPoolT : public MemPool
448447
DynArray< Block*, 10 > _blockPtrs;
449448
Item* _root;
450449

451-
int _currentAllocs;
452-
int _nAllocs;
453-
int _maxAllocs;
454-
int _nUntracked;
450+
size_t _currentAllocs;
451+
size_t _nAllocs;
452+
size_t _maxAllocs;
453+
size_t _nUntracked;
455454
};
456455

457456

@@ -1981,11 +1980,11 @@ class TINYXML2_LIB XMLDocument : public XMLNode
19811980
void PushDepth();
19821981
void PopDepth();
19831982

1984-
template<class NodeType, int PoolElementSize>
1983+
template<class NodeType, size_t PoolElementSize>
19851984
NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );
19861985
};
19871986

1988-
template<class NodeType, int PoolElementSize>
1987+
template<class NodeType, size_t PoolElementSize>
19891988
inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )
19901989
{
19911990
TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );

0 commit comments

Comments
 (0)