Make QVarLengthArray exception safe in case of OOM

After a exception is thrown in resize(), QVarLengthArray has an
invalid state with ptr == 0. On the next resize call when malloc
returns a valid pointer, oldPtr is 0 and it could crash in
memcpy because the pointer to the source is 0.
The patch ensures the valid pointer isn't overwritten with NULL.
When exceptions are disabled the user must ensure that malloc will
not fail.

Change-Id: Id12a5e3e1eacc551e4d1b64cba8e8414cfebd6e1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Peter Kümmel 2012-10-10 16:17:08 +02:00 committed by The Qt Project
parent 191c0e300b
commit a47f21edd6

View File

@ -252,35 +252,31 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::realloc(int asize, int a
const int copySize = qMin(asize, osize);
if (aalloc != a) {
ptr = reinterpret_cast<T *>(malloc(aalloc * sizeof(T)));
Q_CHECK_PTR(ptr);
if (ptr) {
s = 0;
a = aalloc;
if (QTypeInfo<T>::isStatic) {
QT_TRY {
// copy all the old elements
while (s < copySize) {
new (ptr+s) T(*(oldPtr+s));
(oldPtr+s)->~T();
s++;
}
} QT_CATCH(...) {
// clean up all the old objects and then free the old ptr
int sClean = s;
while (sClean < osize)
(oldPtr+(sClean++))->~T();
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
free(oldPtr);
QT_RETHROW;
T* newPtr = reinterpret_cast<T *>(malloc(aalloc * sizeof(T)));
Q_CHECK_PTR(newPtr); // could throw
// by design: in case of QT_NO_EXCEPTIONS malloc must not fail or it crashes here
ptr = newPtr;
s = 0;
a = aalloc;
if (QTypeInfo<T>::isStatic) {
QT_TRY {
// copy all the old elements
while (s < copySize) {
new (ptr+s) T(*(oldPtr+s));
(oldPtr+s)->~T();
s++;
}
} else {
memcpy(ptr, oldPtr, copySize * sizeof(T));
} QT_CATCH(...) {
// clean up all the old objects and then free the old ptr
int sClean = s;
while (sClean < osize)
(oldPtr+(sClean++))->~T();
if (oldPtr != reinterpret_cast<T *>(array) && oldPtr != ptr)
free(oldPtr);
QT_RETHROW;
}
} else {
ptr = oldPtr;
return;
memcpy(ptr, oldPtr, copySize * sizeof(T));
}
}
s = copySize;