Search code examples
xmlqtrandomqt4qt5

Qt 5 produce random attribute order in XML


When switching from Qt 4.8 to Qt 5.x you may notice that each time you save XML document it produce random attribute order inside the file. It makes no problem for programaticaly reading the XML document because attributes are allowed to be stored in any order when XML is deserialized. It is a problem when you track changes of output XML files using GIT, SVN, etc. - it is not possible to tell if the data inside XML file changed or the attribute structure changed.

Is it possible to generate XML files in Qt 5.x the same way as in Qt 4.8?


Solution

  • It is not possible to generate the same way as in Qt 4.8 which saved XML attributes the same order it read them. But there is a way to get rid off the randomness and generate the XML files always with the same order which may or may not be the same order it read them. In other words repeated saved will produce same results.

    Why Qt 5.x save attributes randomly? Because it uses QHash to store the attributes and QHash class has been modified to patch algorithmic complexity attacks which is described here: http://qt-project.org/doc/qt-5/qhash.html#algorithmic-complexity-attacks

    If you are using QHash to store some data in specific order then switching to Qt 5.x will break your code.

    The solution:

    1) Lock the hash seed using evironment variable:

    void main( void )
    {
        qputenv("QT_HASH_SEED", "0");
        ...
    }
    

    It will lock the hash seed to one value between processes and will produce the same XML output everytime.

    Iv noticed that eveything is fine until I run the program on the other machine - then the output is again different but the same everytime I save the XML.

    2) Lock the hash seed using global variable

    extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
    void main( void )
    {
        qt_qhash_seed.store(0);
        ...
    }
    

    This time Iv got the same output between processes and between computers which is more or less the same way as saved using Qt 4.8.