Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-40029

QList<QString> toSet() AddressSanitizer: heap-buffer-overflow (32 bit only)

    XMLWordPrintable

Details

    • 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

        Activity

          People

            thiago Thiago Macieira
            richard.maxwell Richard Maxwell
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes