Internal Qt bug or incorrect user API call?



  • What does "this line":https://qt.gitorious.org/qt/digia-qt/source/705b0f958a6071341b10cbd51917e1378356491b:src/corelib/tools/qvarlengtharray.h#L194this line do?
    I am referring to the line

    @new (ptr+(s++)) T(*abuf++);@

    in this function:

    @
    template <class T, int Prealloc>
    Q_OUTOFLINE_TEMPLATE void QVarLengthArray<T, Prealloc>::append(const T *abuf, int increment)
    {
    Q_ASSERT(abuf);
    if (increment <= 0)
    return;

    const int asize = s + increment;
    
    if (asize >= a)
        realloc(s, qMax(s*2, asize));
    
    if (QTypeInfo<T>::isComplex) {
        // call constructor for new objects (which can throw)
        while (s < asize)
            new (ptr+(s++)) T(*abuf++);
    } else {
        qMemCopy(&ptr[s], abuf, increment * sizeof(T));
        s = asize;
    }
    

    }
    @

    It looks to me like an explicit memory leak ("see new()":http://en.cppreference.com/w/cpp/language/new).
    It expressly allocates dynamic memory and does not store the pointer anywhere, unless Qt has its own allocation implementation (ie "set_new_handler()":http://en.cppreference.com/w/cpp/memory/new/set_new_handler).

    I am asking because I am seeing random crashes in my ODBC application when retrieving an output parameter.
    Tracing the call, it's coming from an access violation attempting to read the location of abuf in the above append() function called from "this line in QODBCResult::exec()":https://qt.gitorious.org/qt/digia-qt/source/705b0f958a6071341b10cbd51917e1378356491b:src/sql/drivers/odbc/qsql_odbc.cpp#L1655.
    @
    array.append((SQLTCHAR *)first.constData(), first.size());
    @

    Normally this pointer seems correct, except when it crashes (debugging in Visual Studio 2012) with a read access violation because this pointer is apparently unreadable. Stepping back to QODBCResult::exec(), the variables seem normal and the output parameter seems to have been retrieved properly.

    What is causing this? How can I fix it?


  • Lifetime Qt Champion

    Hi,

    Pretty low-level, you should bring this on the interest mailing list, you'll find there Qt's developers/maintainers (this forum is more user oriented)



  • I was hoping there's some obvious way I'm misusing the Qt SQL/ODBC API.


  • Moderators

    [quote author="superqt" date="1407540721"]What does "this line":https://qt.gitorious.org/qt/digia-qt/source/705b0f958a6071341b10cbd51917e1378356491b:src/corelib/tools/qvarlengtharray.h#L194this line do?
    I am referring to the line

    @new (ptr+(s++)) T(*abuf++);@
    [/quote]That's called placement new (see http://madebyevan.com/obscure-cpp-features/ ). It constructs a new instance of class T and stores the newly-allocated object at memory location ptr+s. It's not a memory leak as the QVarLengthArray knows exactly where to find the object.

    I'm don't know what's causing your crash though.



  • I was aware of placement new but not having used this much myself, I thought the first parameter was the size, not the pointer. I think I was confounding the new-expression with the new operator called by the new-expression. Thanks for pointing that out.

    What could cause dereferencing the pointer as described to turn into a read access violation? Is it possible for that to happen given only the code I mentioned, or would there have to be something else interfering with the memory?


  • Moderators

    [quote]What could cause dereferencing the pointer as described to turn into a read access violation?[/quote]You get a read access violation when you try to read from a part of memory which doesn't belong to you. Examples include dereferencing an uninitialized pointer, or dereferencing a pointer which has already been freed.

    [quote]Is it possible for that to happen given only the code I mentioned, or would there have to be something else interfering with the memory?[/quote]I'm afraid I don't know. There's a memory bug somewhere, but those aren't easy to track down. It could be in Qt code or your code.

    Do you have a memory debugger?



  • Thank you for your reply. Any assistance is much appreciated!

    bq. Do you have a memory debugger?

    Yes, I do. I am debugging in Visual Studio 2012, which generally works well. When I said "to turn into a read access violation" the emphasis is on "turn into". In the code of the append() function I posted, the read access violation occurs around iteration 300 out of 500. That is, realloc() or other internal allocation of QVarLengthArray should have access to the full range of memory assigned to the internal ptr variable, which should include the range described by abuf. Instead, it appears that read access is lost after partially iterating the buffer.

    The only way I can think of that the incrementations of abuf would direct the loop in QVarLengthArray::append() to unreadable memory would be if abuf or increment was not allocated properly (edit: or if something else is concurrently freeing over overwriting the memory accessed during this iteration). How can I determine if this problem originates in QODBCResult::exec() before it makes the call to QVarLengthArray::append()? Could this be a problem with the buffer bound to the query object in my user code?

    Unfortunately it is difficult to track what is happening in the iterations before the read access violation, because although I can set an automatic breakpoint when the read access violation is detected, QVarLengthArray::append() and the QODBCResult::exec() are called many (hundreds/thousands) times before the intermittent error manifests. I could manually step through the code in question a hundred thousand times and the error would still never trigger if it is caused by something like a runtime execution timing issue, especially if the interaction involves other processes not involved in debugging.


  • Moderators

    I didn't mean a generic debugger, but a memory debugger -- something like Valgrind, which identifies problems such as memory leaks and attempts to access uninitialized/freed pointers.

    Your symptoms remind me of a problem I had in my early days of C programming: I recursively called realloc(), but forgot to initialize the original pointer to NULL before passing it into realloc(). Everything seemed ok if my program ran for less than 50 iterations, but it crashed if more iterations were required.

    I'm not familiar with the internals of QVarLengthArray or QODBCResult and I can't think of a simple path towards a solution to your problem, but you may be interested to know that even Qt engineers come across strange crashes now and then: http://www.marshut.net/kkhirt/crash-when-activating-timers.html If you subscribe to the "Interest mailing list":http://lists.qt-project.org/mailman/listinfo/interest and post your problem there, you might get the aid of someone more capable than myself.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.