[SOLVED] QString.at(), debug, VC++ Rt error if string empty (Qt 5.5.0)



  • I was running some code that used a QString array and the method at() on an item. It compiled just fine but, as soon as the application started, it thrown a Visual C++ Runtime error. The error only happens in debug mode. The code I'm running is in a class, the important part is this:

    class something{
    enum errorLevel{
        EL_NONE=0,
        EL_INFO,
        EL_WARNING,
        EL_ERROR
    };
    
    // ....
    void print(QString message, errorLevel EL){
        QString tmpMsg;
        // some other code...
    	QString el_msg[4] = {"", "info", "warning", "error"};
        tmpMsg.replace("%e" ,  el_msg[EL].at(0));
    }
    };
    

    Sometimes the VC++ error message would also report an issue at line 851 in file qstring.h. Next there is the code at line 850-851 in that file:

    inline const QChar QString::at(int i) const
    { Q_ASSERT(uint(i) < uint(size())); return d->data()[i]; }
    

    The problem seems to be that the assertion fails, as reported by Qt Creator's Application output panel:

    ASSERT: "uint(i) < uint(size())" in file D:/DevTools/qt-builds/qt-5.5.0-x64-mingw510r0-sjlj/include/QtCore/qstring.h, line 851
    

    The error only happens with an empty ( "" ) string. Anything else seems to be ok.
    I would report that to the developers but it might also be an issue in the VC++ RT library. Does this error happen to anyone? Or maybe it has been fixed already in a newer Qt release?



  • Hi,

    as I see it, it should only crash when you pass in EL_NONE as the errorLevel parameter.
    In this line tmpMsg.replace("%e" , el_msg[EL].at(0)); you grab the QString at position 0 (since EL_NONE=0) from the QString array.
    The QString you get is empty, but still you try to get the character at position 0 (with at(0)) and this is where the program crashes, since there is nothing at this position.

    Btw this is what the ASSERT is trying to tell you. The parameter i which you pass into at(int i) is bigger than the size of the QString object.

    Hope this helps!
    Tobi



  • Yes, I understand that getting a character from an empty string fails. However, this behaviour is wrong.
    Getting a character from an empty string should return an empty string, not fail. At most, a warning or an error should be raised in debug mode, but not in any case should that small error crash the application like it happens now.
    If we accepted this wrong behaviour then QString::chop() should fail as well on an empty string, as well as most of the other methods available in the QString class (such as remove, replace, left, right and so on).

    BTW I worked around the problem by using a space instead of an empty string


  • Moderators

    "However, this behaviour is wrong." - no, it isn't.
    Please check the QString documentation:
    const QChar QString::at(int position) const
    Returns the character at the given index position in the string.
    The position must be a valid index position in the string (i.e., 0 <= position < size()).


  • Moderators

    @T3STY said:

    Getting a character from an empty string should return an empty string, not fail.

    No, @jsulm is correct.

    In essence, a string is an array of characters. In C++, if you try to retrieve an array element that is beyond the array's range, your program will crash:

    int intArray[] = {1, 2, 3, 4, 5};
    int i = intArray[7]; // Crash!
    
    QString str1("Hello");
    str1[0]; // OK, returns 'H'
    str1[7]; // Crash!
    str1.at(7); // Crash!
    
    QString str2;
    str2[0]; // Crash!
    str2.at(0); // Crash!
    

    Accessing items outside of an array's range is forbidden in C++: http://www.cplusplus.com/reference/stdexcept/out_of_range/

    If we accepted this wrong behaviour then QString::chop() should fail as well on an empty string

    That function is designed to perform checks to make sure that the range is valid.

    However, if we did that for QString, std::vector, or others, the performance of some applications will grind to a halt. So, it's the programmer's responsibility to ensure that you don't access items out of an array's range.



  • OK, I'll keep my workaround space until I'll find some other solution.
    However I still think you should not crash the program upon such thing. After all, QString is a class built specifically to make it easier to work on strings, which implies to avoid out of bounds crashes, full of rarely used methods and full of other checks to make sure everything is fine. I think a simple check if (size() <= 0) return ""; will not impact that much on performance...

    p.s. If you don't make that check in the QString class, it means the user has to make it. Either way, there is a check to make and a performance loss anyway.


  • Moderators

    @T3STY said:

    I still think you should not crash the program upon such thing. After all, QString is a class built specifically to make it easier to work on strings, which implies to avoid out of bounds crashes, full of rarely used methods and full of other checks to make sure everything is fine.

    If you believe that Qt should change its design, I recommend you subscribe to the Development mailing list and post there. Qt's engineers are active on that list; you can present your suggestion to them directly.

    I think a simple check if (size() <= 0) return ""; will not impact that much on performance...

    See http://stackoverflow.com/questions/24312601/is-bounds-checking-in-c-or-c-expensive

    p.s. If you don't make that check in the QString class, it means the user has to make it. Either way, there is a check to make and a performance loss anyway.

    There's a big difference between checking only when required versus checking every single character in the string.


Log in to reply
 

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