Details
-
Bug
-
Resolution: Done
-
P4: Low
-
4.8.2, 4.8.6, 5.3.1
-
{noformat}
uname -a
Linux honey 3.15.2-1-ARCH #1 SMP PREEMPT Fri Jun 27 07:41:19 CEST 2014 x86_64 GNU/Linux
{noformat}
-
813af5f0655c332b2853d156b91c5265b85cbc70 (dev, 8.7.2014,5.4)
Description
Enabling GCC's implementaiton of clang's address sanitiser results in a crash inside Qt's QHashNode function.
This only happens on 32 bit x86 builds. 64 bit builds do not trigger the error.
I have tested this on Qt 4.8.2, 4.8.6 and 5.3.0. All fail in the same way.
==12449==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf50007d0 at pc 0x804bc72 bp 0xffc919b8 sp 0xffc919a8 WRITE of size 16 at 0xf50007d0 thread T0 #0 0x804bc71 in QHashNode<QString, QHashDummyValue>::~QHashNode() /usr/include/qt4/QtCore/qhash.h:216 #1 0x804bcb3 in QHash<QString, QHashDummyValue>::deleteNode2(QHashData::Node*) /usr/include/qt4/QtCore/qhash.h:521 #2 0xf6fe7dcb in QHashData::free_helper(void (*)(QHashData::Node*)) (/usr/lib32/libQtCore.so.4+0x83dcb) #3 0x804af1a in QHash<QString, QHashDummyValue>::freeData(QHashData*) /usr/include/qt4/QtCore/qhash.h:570 #4 0x804a531 in QHash<QString, QHashDummyValue>::~QHash() /usr/include/qt4/QtCore/qhash.h:283 #5 0x804a10f in QSet<QString>::~QSet() /usr/include/qt4/QtCore/qset.h:54 #6 0x80493c6 in main ../StringListToSetAddressSanitiserTest/main.cpp:15 #7 0xf6ca7e2d in __libc_start_main (/usr/lib32/libc.so.6+0x17e2d) #8 0x80490f0 (/home/jodi/Code/build-StringListToSetAddressSanitiserTest-32Bit_GCC_Qt_4_8-Debug/StringListToSetAddressSanitiserTest+0x80490f0) 0xf50007dc is located 0 bytes to the right of 12-byte region [0xf50007d0,0xf50007dc) allocated by thread T0 here: #0 0xf729c08c in malloc (/usr/lib32/libasan.so.1+0x5108c) #1 0xf6fc34ca in qMalloc(unsigned int) (/usr/lib32/libQtCore.so.4+0x5f4ca) #2 0x804ba46 in QHash<QString, QHashDummyValue>::insert(QString const&, QHashDummyValue const&) /usr/include/qt4/QtCore/qhash.h:763 #3 0x804aeae in QSet<QString>::insert(QString const&) /usr/include/qt4/QtCore/qset.h:181 #4 0x804a430 in QList<QString>::toSet() const /usr/include/qt4/QtCore/qset.h:314 #5 0x804930d in main ../StringListToSetAddressSanitiserTest/main.cpp:15 #6 0xf6ca7e2d in __libc_start_main (/usr/lib32/libc.so.6+0x17e2d) SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/include/qt4/QtCore/qhash.h:216 QHashNode<QString, QHashDummyValue>::~QHashNode() Shadow bytes around the buggy address: 0x3ea000a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea000b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea000c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea000d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea000e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x3ea000f0: fa fa fa fa fa fa fa fa fa fa[00]04 fa fa 00 04 0x3ea00100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea00110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea00120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea00130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x3ea00140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Contiguous container OOB:fc ASan internal: fe
QMAKE_CXXFLAGS += -fsanitize=address -fno-omit-frame-pointer QMAKE_CFLAGS += -fsanitize=address -fno-omit-frame-pointer QMAKE_LFLAGS += -fsanitize=address
I poked around the internals and it seems that the reason for this is because
deleteNode2 is casting a DummyNode pointer to a Node pointer. The size of the dummy node is 12 bytes, while the Node is 16 bytes.
Creation
QHash<Key, T>::createNode(uint ah, const Key &akey, const T &avalue, Node **anextNode) { Node *node; if (QTypeInfo<T>::isDummy) { node = reinterpret_cast<Node *>(new (d->allocateNode(alignOfDummyNode())) DummyNode(akey)); // <---- created here
Destruction
template <class Key, class T> Q_INLINE_TEMPLATE void QHash<Key, T>::deleteNode2(QHashData::Node *node) { #ifdef Q_CC_BOR concrete(node)->~QHashNode<Key, T>(); #else concrete(node)->~Node(); // <---- deleted here, but it's a dummy node! #endif }
Attachments
For Gerrit Dashboard: QTBUG-40029 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
88983,1 | Don't destroy a QHash::DummyNode as if it were QHash::Node | dev | qt/qtbase | Status: ABANDONED | -1 | 0 |
89040,5 | Remove QHashDummyNode and avoid undifined behavior | dev | qt/qtbase | Status: MERGED | +2 | 0 |