Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.6.0
-
Ubuntu 14.04 x86_64, and Qt 5.6.0 built from the source archive
-
fc1ab49cd75608f257fb9aa577fed490c5a8e551 (qt/qtbase/5.12)
Description
In QContiguousCache::setCapacity, not all fields of QContiguousCacheData are initialized after the new data is allocated, including the reference count d->ref.
Since the reference count will be an arbitrary number after setCapacity is called, the data may not be freed after the destructor is called.
This error (memory leak and use of uninitialized data) was found by the dynamic analysis tool Pareon Verify. Here's an excerpt of the report we get when analyzing tst_qcontiguouscache:
[M0181] Memory leak detected: the heap object of size 632 allocated through a call to `realloc' in function qReallocAligned(void*, unsigned long, unsigned long, unsigned long) at qtbase/src/corelib/global/qmalloc.cpp:81 called from function qMallocAligned(unsigned long, unsigned long) at qtbase/src/corelib/global/qmalloc.cpp:70 called from function QContiguousCacheData::allocateData(int, int) at qtbase/src/corelib/tools/qcontiguouscache.cpp:53 called from function QContiguousCache<int>::allocateData(int) at qtbase/src/corelib/tools/qcontiguouscache.h:276 called from function QContiguousCache<int>::setCapacity(int) at qtbase/src/corelib/tools/qcontiguouscache.h:212 called from function tst_QContiguousCache::setCapacity() at qtbase/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp:338 (...) ^^^ application start ^^^ has become unreachable. This object was last accessible as the result of the call to function `QContiguousCache<int>::at(int) const' in function tst_QContiguousCache::setCapacity() at qtbase/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp:347 (...) ^^^ application start ^^^ This object was last accessed by: the atomic memory access in function std::__atomic_base<int>::operator--() called from function bool QAtomicOps<int>::deref<int>(std::atomic<int>&) at qtbase/src/corelib/arch/qatomic_cxx11.h:140 called from function QBasicAtomicInteger<int>::deref() at qtbase/src/corelib/thread/qbasicatomic.h:132 called from function QContiguousCache<int>::detach_helper() at qtbase/src/corelib/tools/qcontiguouscache.h:200 called from function QContiguousCache<int>::detach() at qtbase/src/corelib/tools/qcontiguouscache.h:97 called from function QContiguousCache<int>::setCapacity(int) at qtbase/src/corelib/tools/qcontiguouscache.h:210 called from function tst_QContiguousCache::setCapacity() at qtbase/tests/auto/corelib/tools/qcontiguouscache/tst_qcontiguouscache.cpp:350 (...) ^^^ application start ^^^
For a possible fix, simply initialize all fields of QContiguousData:
diff --git a/qtbase/src/corelib/tools/qcontiguouscache.h b/qtbase/src/corelib/tools/qcontiguouscache.h index 41d198f..79515bc 100644 --- a/qtbase/src/corelib/tools/qcontiguouscache.h +++ b/qtbase/src/corelib/tools/qcontiguouscache.h @@ -210,6 +210,9 @@ void QContiguousCache<T>::setCapacity(int asize) detach(); union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x; x.d = allocateData(asize); + x.d->ref.store(1); + x.d->sharable = true; + x.d->reserved = 0; x.d->alloc = asize; x.d->count = qMin(d->count, asize); x.d->offset = d->offset + d->count - x.d->count;