Qt5 application crashed with error 0xc0000005

This is very interesting crash and I think it should be considered as Qt bug. This problem arise only under very special circumstances. But one after another.

You will identify this problem when your application stopped/exited immediately after the start without any visible error message. It looks like the application isn’t executed at all. When you check application log (Computer -> manage -> Event viewer -> Windows logs -> Application), you will see Error logs:

Windows applications logs

The most interesting part of this log is crash location: ntdll.dll

Faulting application name: Skipper.exe, version: 3.0.1.1120, time stamp: 0x53e9c8d7
Faulting module name: ntdll.dll, version: 6.1.7601.18247, time stamp: 0x521ea8e7
Exception code: 0xc0000005
Fault offset: 0x0002e3be
Faulting process id: 0x1c88
Faulting application start time: 0x01cfb606553e594b
Faulting application path: T:\S2\Skipper.exe
Faulting module path: C:\Windows\SysWOW64\ntdll.dll
Report Id: 98cc8228-21f9-11e4-ab5d-005056c00008

At first sight it seems like some problem inside the windows. But the opposite is true, the problem (as almost always) is inside your app ;-).

As the next step, you can try to debug this executable via Visual Studio to see what happens inside. Simply open executable as project together with .pdb files and execute it. Now you can see that application is correctly executed but crashes as soon as it touches Qt library. The location of crash is inside ntdll.dll in RtlHeapFree() function.

Debuging crash in VisualStudio 2013

So the problem is inside the Qt, right? Almost true, but not for the 100%. When I tried to run this application on computers of my colleagues, everything works ok. So why the application doesn’t work on my computer too?

Resolution

The problem is in new Qt5 plugin system. Besides the common Qt5*.dll files which are loaded immediately after the application start, Qt5 is also loading plugins/platform-plugins dynamically when the application is executed. To locate this plugins, Qt5 uses following method to identify directories where to search for plugins:

QStringList QCoreApplication::libraryPaths()

For some strange reason this library returns as first directory path where Qt5 libraries were compiled and after that location based on the executable. So if your Qt5 path is C:\Qt5, this will be the first path where all plugins are searched for, no matter if the correct version of plugin is located in APP\plugins or APP\platforms. I think this is serious bug in Qt5.

Where is the problem?

And here we’re getting to the core of the whole problem.

If application is compiled on computer with one compiler and used on second  computer which contains the same path to which original computer has installed Qt, the application will load all plugins from your folder instead of itself folder.

In case your computer will contain different version of Qt, different compiler or different platform, application loads incorrect libraries and crashes. Completely, silently and without easy way to determine what’s wrong.

Solution?

The solution is simple, but it isn’t achievable from outside of the Qt library. It would be necessary to Qt as first tried to load libraries from application directory. And only if no plugins were found in application directory, the application would try to search for plugins in Qt directory.

Qt change solution

The simplest way how to fix this issue inside the Qt library would be to rename/update appendApplicationPathToLibraryPaths  function to prependApplicationPathToLibraryPaths and change

void QCoreApplicationPrivate::prependApplicationPathToLibraryPaths()
{
#ifndef QT_NO_LIBRARY
    QStringList *app_libpaths = coreappdata()->app_libpaths;
    if (!app_libpaths)
        coreappdata()->app_libpaths = app_libpaths = new QStringList;
    QString app_location = QCoreApplication::applicationFilePath();
    app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
#ifdef Q_OS_WINRT
    if (app_location.isEmpty())
        app_location.append(QLatin1Char('/'));
#endif
    app_location = QDir(app_location).canonicalPath();
    if (QFile::exists(app_location) && !app_libpaths->contains(app_location))
        //CHANGE THIS ROW: app_libpaths->append(app_location);
        //TO FOLLOWING
        app_libpaths->prepend(app_location);
#endif
}

InApp solution

Unfortunately it isn’t possible to simply change this behavior from your app. All of these operations happen directly in QCoreApplication constructor so if you try to change it after, it’s too late.

The temporary solution before this problem will be resolved is to reinitialize library paths before QCoreApplication is initialized. It’s necessary to clean libray paths, compute new paths and re-initialize QCoreApplication::libraryPaths before QCoreApplication object is initialized. This can be done in main.cpp of your application before you will create QApplication/QCoreApplication object.

  QString executable = argv[0];
  QString executablePath = executable.mid(0,executable.lastIndexOf("\\"));
  QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
  QCoreApplication::removeLibraryPath(installPathPlugins);
  QCoreApplication::addLibraryPath(installPathPlugins);
  QCoreApplication::addLibraryPath(executablePath);

It’s not a nice solution, but it works. I tried  to report this issue also to bugreports.QtProject, so maybe in later version this will be fixed.

4 comments

  1. I have the same issue. Have you heard anything from the Qt developers on this bug?

    1. Unfortunately yes. As you can see in bug report on Qt project, they marked is as “default and expected behavior” for current release and they don’t plan to modify it ;-(

  2. maybe you can fix that with a qt.conf file next to the QtCore library …
    content could be (untested):
    Prefix= ./
    or
    Prefix=

    with that you it should be possible to overwrite the origin install path to that relative path

    1. I Have the same issue.

      I have add

      int main(int argc, char *argv[])
      {

      QString executable = argv[0];
      QString executablePath = executable.mid(0,executable.lastIndexOf(“\\”));
      QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath);
      QCoreApplication::removeLibraryPath(installPathPlugins);
      QCoreApplication::addLibraryPath(installPathPlugins);
      QCoreApplication::addLibraryPath(executablePath);

      But its not working 🙁

      any idea ?

Leave a Reply

Your email address will not be published. Required fields are marked *