Q_ASSERT no longer pauses debugger



  • Hi there,

    Please forgive me if this is a well known issue, I've searched the forum and couldn't find anything, although I can't imagine I'm the first one this is a problem for. I've noticed that in the last few versions of Qt Creator for Windows, Q_ASSERT no longer pauses the debugger but rather just crashes the application. This is a huge problem for me since my project uses Q_ASSERTs very liberally. I tried checking 'Stop when qWarning is issued' and 'Stop when qFatal is issued' under Options->Debugger->GDB, but in that case the application won't even load in debug mode. Is there any way at all to restore the debugger-pausing functionality of Q_ASSERT from previous versions of Qt Creator?

    Thanks, Nir


  • Moderators

    It sais in Qt Assistant
    @
    If b is zero, the Q_ASSERT statement will output the following message using the qFatal() function:
    @
    Under the debugging techniques is sais:
    @
    qFatal() is used for writing fatal error messages shortly before exiting.
    @
    Reading this, your debugger seems to behave as expected.
    This seems to complyant with the behaviour of "assert" under ms compilers.



    1. Are you sure your application is compiled in debug mode?
    2. Can you try to manually put a breakpoint on qFatal and see if you hit it?


  • koahnig: I totally get that. I understand if pausing the debugger when a Q_ASSERT fails was just a freebie in previous versions of Qt Creator, but I'd love to have something like that again. Even if it's a different mechanism that does the same thing, ie pause the debugger when a condition fails. Also I find it odd that the application won't start at all in debug mode if the 'stop at qFatal/qWarning' options are checked.

    peppe: Absolutely. The application debugs just fine. It just crashes when a Q_ASSERT fails. I set a breakpoint on a qFatal call as you've suggested and it gets there just fine, then of course proceeds to crash when resumed :)



  • I should have posted this earlier, I did some digging into this problem a couple of months ago (I've been dealing with it for a while :) and ended up finding this bug report: https://bugreports.qt.nokia.com/browse/QTCREATORBUG-5200 . I couldn't remember how it relates but indeed when stop on qWarning/qFatal are checked I get:

    (Internal error: pc 0x0 in read in psymtab, but not in symtab.)

    and sometimes:

    (Internal error: pc 0x6 in read in psymtab, but not in symtab.)

    in the application output window.

    Many of the related issues listed echo the kind of trouble I've been experiencing. The bug is not yet evaluated however.



  • Well, the application is supposed to "crash" when a Q_ASSERT fails*! :-)
    What's the strange behaviour in that?

    • This applies of course to debug builds only, release builds expand Q_ASSERT to nothing. The "crash" is calling abort(3) under *nix systems.

  • Moderators

    [quote author="nirslsk" date="1325919907"]koahnig: I totally get that. I understand if pausing the debugger when a Q_ASSERT fails was just a freebie in previous versions of Qt Creator, but I'd love to have something like that again.
    [/quote]
    I am wondering if this was really a feature of qt creator. Since I am a mere user of debugger than one knowing the functionality and interaction per se, I might be wrong.
    However, to my understanding is qt creator a shell using different debuggers depending on the tool chains. It is not a simple shell, but has certainly enough hooks into the debuggers to perform a lot of things. The debugger itself is used somehow again as a shell for the program to be debugged. Again it is using hooks for "communicating" with the program. There are possibilities to manipulate the conditions within the debuggee. Finally the program is executing and it will crash under certain conditions.
    Some debuggers may be or are able to overwrite those conditions. However, do they provide also the hooks for creator?

    This description is certainly very, very simplistic of the whole situation. However, it leads to a point. The application your program is crashing. Seeing the complexity of the different stages of debugging process the question is wasn't it a bug in previous Qt version and not the creator which allowed keeping your application running?



  • What is the 'Stop when qFatal is issued' option supposed to do then?


  • Moderators

    Judging by the name qFatal I would connect immediately to "no recovery possible" and "will not continue". What is more than fatal?
    Therefore, it is "natural" that there nothing afterwards.



  • @nirslsk
    Could you point me to where you put that breakpoint exactly? I tried putting one, but the place where I tried did not seem to trigger (C:\QtSDK\QtSources\4.7.4\src\corelib\global\qglobal.cpp line 2518)



  • Hi Andre,

    I didn't actually put a breakpoint in the qFatal function... I don't think my Qt Creator setup is configured to work with the actual Qt sources. I put the breakpoint in my own code on a line where qFatal is being called.



  • OK, my issue was finding that line :-)

    It seems the root cause is actually a Qt Creator bug. Something is fishy when trying to set a breakpoint near qFatal itself.

    This is my temporary solution. Insert the below in main.cpp

    @
    //debugging asserts in Qt code is tricky with MinGw. You get a crash, instead of a backtrace.
    //enable the define below to get a crash that results in a backtrace instead. Note that it does
    //mess up your debug output, so don't leave it enabled if you're not working on fixing an assert
    #define DEBUG_QT_ASSERT

    #ifdef DEBUG_QT_ASSERT
    void crashMessageOutput(QtMsgType type, const char *msg)
    {
    switch (type) {
    case QtDebugMsg:
    fprintf(stderr, "Debug: %s\n", msg);
    break;
    case QtWarningMsg:
    fprintf(stderr, "Warning: %s\n", msg);
    break;
    case QtCriticalMsg:
    fprintf(stderr, "Critical: %s\n", msg);
    break;
    case QtFatalMsg:
    fprintf(stderr, "Fatal: %s\n", msg);
    __asm("int3");
    abort();
    }
    }
    #endif

    int main(int argc, char *argv[])
    {
    #ifdef DEBUG_QT_ASSERT
    qInstallMsgHandler(crashMessageOutput);
    #endif

    QApplication a(argc, argv);
    
    //etc. rest of main function
    

    }
    @



  • Thank you! That's already much better than the near empty crash message I currently get on a Q_ASSERT failure. Actually one thing I've found that works well for me is replacing the Q_ASSERTs in my program with a simple function that writes to a null pointer if the condition given is false:

    @void CrashAssert (bool i_condition)
    {
    #ifdef DEBUG
    if (! i_condition)
    {
    int * a = 0; *a = 0;
    }
    #endif
    }@

    (I take care to define the DEBUG macro in my project settings, I understand you can also ifndef QT_NO_DEBUG instead)

    What happens then is that I actually get the debugger to stop at the point of the condition failure. I can't resume the program execution as when Q_ASSERT used to pause the debugger, but I can inspect the stack in detail and look at each variable as usual. Not the most elegant solution in the world, but it's worked well so far :)

    Thanks much, Nir



  • Nice thing about my work-around, is that it is also useful for asserts inside the Qt library itself. For instance, if you call QList::at() with an out of bounds index, you get an assert. With the piece of code I posted, this now results in a stacktrace where you can figure out where that call to QList::at() is actually made in your own code. Also, my version will never be optimized out by a compiler. I think that yours may be, but I'm not sure.

    It would be much better if such a hack was not needed though.



  • True, I'll be sure to alternate between the two solutions as my needs change. Here's hoping for the return of Q_ASSERT's functionality of yore :)



  • This was driving me mad as well, I ended up abandoning Q_ASSERT altogether and implemented my own simple SCASSERT (for Stop and Continue Assert) for when using Qt Creator with MinGW and GDB:

    @
    #define SCASSERT(cond)
    {
    if (!(cond))
    {
    qDebug("ASSERT: %s in %s (%s:%u)",
    #cond, PRETTY_FUNCTION, FILE, LINE);
    asm("int $3");
    }
    }
    @

    This will break into the debugger on the line of the assert and allow you to continue afterwards should you choose to.



  • @sharevari Very good! Thank you. I had to reformat and make some changes to get it to run on my Linux Mint system. I also added the options for using either it, Q_ASSERT or turning it off by just changing a number in the first line (0, 1 or 2).

    #define ASSRT 2
    #if ASSRT == 1
    #define SCASSERT Q_ASSERT
    #elif ASSRT == 2
    #define SCASSERT(cond) {\
        if (!(cond)) {\
            qDebug("ASSERT: %s in %s (%s:%u)",#cond, Q_FUNC_INFO, __FILE__, __LINE__);\
            asm("int $3");\
        }\
    }
    #else
    #define SCASSERT(cond) {}
    #endif
    
    

    Notice the backslashes at the ends of the multi-line definition.


Log in to reply
 

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