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

QString::toUpper() fails at temporary objects with c++11 if resulting string grows

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.6.0
    • 5.5.0, 5.5.1
    • None

    Description

      If toUpper is called on a temporary QString and the QString contains a character which expands to two or more letters (for example the german ligature ß (szett) expands to SS) the result is wrong.

      The problematic code

      template <typename Traits, typename T>
      Q_NEVER_INLINE
      static QString detachAndConvertCase(T &str, QStringIterator it)
      {
          QString s = qMove(str);             // will copy if T is const QString
          QChar *pp = s.begin() + it.index(); // will detach if necessary
          uint uc = it.nextUnchecked();
          forever {
              const QUnicodeTables::Properties *prop = qGetProp(uc);
              signed short caseDiff = Traits::caseDiff(prop);
      
              if (Q_UNLIKELY(Traits::caseSpecial(prop))) {
                  // slow path
                  const ushort *specialCase = specialCaseMap + caseDiff;
                  ushort length = *specialCase++;
                  int pos = pp - s.constBegin();
                  s.replace(pos, 1, reinterpret_cast<const QChar *>(specialCase), length);
                  pp = const_cast<QChar *>(s.constBegin()) + pos + length;
              } else if (QChar::requiresSurrogates(uc)) {
                  *pp++ = QChar::highSurrogate(uc + caseDiff);
                  *pp++ = QChar::lowSurrogate(uc + caseDiff);
              } else {
                  *pp++ = QChar(uc + caseDiff);
              }
      
              if (!it.hasNext())
                  return s;
      
              uc = it.nextUnchecked();
          }
      }
      

      With C++ 11 and a temporary QString
      QString detachAndConvertCase(T &str, QStringIterator it) gets calls as
      QString detachAndConvertCase(QString &str, QStringIterator it), if not C++11 or not a temporary QString
      QString detachAndConvertCase(const QString &str, QStringIterator it) gets calls.

      The iterator it points to str but it should point to s.

      Luckily with a const str the it always points to the next character, but with a moved QString it falls behind if the "slow path" is chosen.

      As a result QString( "ß_demo" ).toUpper() becomes "SSSSSSS" instead of "SS_DEMO"

      Reproducible with

      • qmake and Xcode7
      • QtCreator with installed Xcode7
      • tried MSVC2015 but it fails to link

      Attachments

        1. main.cpp
          0.9 kB
          Martin Sander
        2. toUpperC11Fail.pro
          0.1 kB
          Martin Sander
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            thiago Thiago Macieira
            yresk Martin Sander
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes