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

QXmlQuery::evaluateTo leaks memory

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Reported
    • Priority: P3: Somewhat important
    • Resolution: Unresolved
    • Affects Version/s: 5.9.1
    • Fix Version/s: None
    • Component/s: XML: QtXmlPatterns
    • Labels:
      None
    • Platform/s:
      macOS

      Description

      The following code using QXmlQuery::evaluateTo(QString *output) leaks memory.

      See the attached Leaks trace leaks_10rep.trace.zip generated using the Leaks utility of Apple's Instruments app. To reproduce it:

      • First compile the qtbug project. (I used release mode)
      • Open Apple's Instruments app.
      • On the top choose the compiled app, i.e. qtbug.app.
      • Choose the Leaks utility.
      • Before starting, click on Leak Checks and then on snapshots on the bottom. Choose 1 second as interval here.
      • Now start the recording using the record button and wait until the record button is visible again indicating that the trace is complete.
      • Click on Leak Checks to see the table of leaks.
      • For higher repetitions make sure to increase the waiting time at the end of the main function otherwise it will not capture all the leaks (ideally the Leaks utility shows a "No new leaks" indicator in the time line)

      Alternatively, just use a high number of repetitions and uncomment the stop() at the end of the main method and then watch the Activity Monitor / Task Manager. About 1MB is leaked per 4 repetitions, so using 400 repetitions makes the app consume about 100MB when stopping.

      See also attachment qtbug70710.zip for a working example with a Qt project file using the same code as below.

      This leak might be related to QTBUG-20830, QTBUG-3628QTBUG-60172, QTBUG-20802,

      #include <iostream>
      #include <thread>
      #include <chrono>
      
      #include <QtCore>
      #include <QXmlQuery>
      
      namespace {
        constexpr int bytesOfOneMB = 1024*1024;
      
        void wasteMemory(const int megaBytes) {
          qInfo("Wasting %d MB now...", megaBytes);
          const int arraysize = megaBytes*bytesOfOneMB;
          char* array = new char[arraysize];
          for(int i=0 ; i<arraysize; ++i) {
            array[i] = 'a';
          }
      //    delete [] array; // omitted to deliberately waste memory
          qInfo("Done");
        }
      
        const QString xml =
            "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n""\n"
            "<root>\n""\n"
      
            "  <term>-1460087571.6437266</term>\n""\n"
            "  <system>minerals</system>\n""\n"
            "  <pot>become</pot>\n""\n"
            "  <bet>1014767728</bet>\n""\n"
            "  <rise>weight</rise>\n""\n"
            "  <excitement>beneath</excitement>\n""\n"
            "  <fast>1606330302.0943468</fast>\n""\n"
            "  <serious>success</serious>\n""\n"
            "  <band>56689147.3003366</band>\n""\n"
            "  <room>order</room>\n""\n"
            "  <difficult>-1846389049.7374732</difficult>\n""\n"
            "  <slabs>1080777107</slabs>\n""\n"
            "  <mile>-1429668644</mile>\n""\n"
            "  <fireplace>-883024560</fireplace>\n""\n"
            "  <exact>desk</exact>\n""\n"
            "  <church>-516291204.614336</church>\n""\n"
            "  <disappear>gift</disappear>\n""\n"
            "  <song>2128439922</song>\n""\n"
            "  <day>2076698251.2718477</day>\n""\n"
            "  <library>1169567673.2849774</library>\n""\n"
            "  <strong>slept</strong>\n""\n"
            "  <factory>friendly</factory>\n""\n"
            "  <broke>1704619180</broke>\n""\n"
            "  <broken>arrow</broken>\n""\n"
            "  <review>tank</review>\n""\n"
            "  <idea>image</idea>\n""\n"
            "  <successful>arrange</successful>\n""\n"
            "  <barn>sheet</barn>\n""\n"
            "  <sat>frame</sat>\n""\n"
            "  <bar>-995623517.5095413</bar>\n""\n"
            "  <different>-827945576.2976611</different>\n""\n"
            "  <saddle>vertical</saddle>\n""\n"
            "  <country>-1294579480</country>\n""\n"
            "  <fine>-210237458.06976008</fine>\n""\n"
            "  <people>shot</people>\n""\n"
            "  <enemy>beneath</enemy>\n""\n"
            "  <lose>wash</lose>\n""\n"
            "  <left>nodded</left>\n""\n"
            "  <underline>302480069</underline>\n""\n"
            "  <journey>349298609.9499917</journey>\n""\n"
            "  <two>855233261</two>\n""\n"
            "  <throughout>policeman</throughout>\n""\n"
            "  <safety>1101445487</safety>\n""\n"
            "  <path>783122588.9262781</path>\n""\n"
            "  <excited>-636194430</excited>\n""\n"
            "  <line>mean</line>\n""\n"
            "  <steam>908359265.9153657</steam>\n""\n"
            "  <gone>-712892793.1713428</gone>\n""\n"
            "  <pitch>684788275</pitch>\n""\n"
            "  <close>-806401825.7013865</close>\n""\n"
            "</root>\n";
      
        const QString xslt =
            "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
            "<xsl:stylesheet version=\"2.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
            "  <xsl:output method=\"xml\" encoding=\"utf-8\" indent=\"yes\" omit-xml-declaration=\"no\"/>\n"
            "  <xsl:template match=\"@* | node()\">\n"
            "     <xsl:copy>\n"
            "        <xsl:apply-templates select=\"@* | node()\"/>\n"
            "     </xsl:copy>\n"
            "  </xsl:template>\n"
            "</xsl:stylesheet>\n";
      
        void testXmlQuery(const int repetitions) {
          qInfo("Testing QXmlQuery now...");
          QXmlQuery xmlQuery(QXmlQuery::XSLT20);
          xmlQuery.setFocus(xml);
          xmlQuery.setQuery(xslt);
          for ( int i = 0; i < repetitions; i++ ) {
            QString resString;
            // The following line seems to leak memory. Comment it out to confirm.
            xmlQuery.evaluateTo(&resString);
          }
          qInfo("Done");
        }
      
        void stop() {
          qInfo("Stopping...");
          std::cin.ignore();
        }
      } // namespace
      
      int main(int argc, char **argv)
      {
        QCoreApplication ca(argc, argv);
      //  wasteMemory(100);
        testXmlQuery(4); // leaks about 1MB per 4 repetitions
      //  stop();
        std::this_thread::sleep_for(std::chrono::seconds(5));
        return 0;
      }
      

       

        Attachments

        1. leaks_10rep.png
          leaks_10rep.png
          422 kB
        2. leaks_10rep.trace.zip
          1.70 MB
        3. qtbug70710.zip
          6 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              boernsen boernsen
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:

                Gerrit Reviews

                There are no open Gerrit changes