Question

I have a program where QApplication is created with the new operator. It crashes for unknown reason. I use RedHat Linux, G++ 4.8.2, Qt 4.7.2 which was built with the same compiler.

This source contains many looking useless but harmless pieces, e.g the 'func' function with four unused arguments. If I try to remove them and simplify the program a bit further the crash can't be reproduced anymore which of course doesn't mean the problem has been solved.

The crash happens in the function strlen, which is called from system function XSetCommand. Adding my own simple implementatioon allowed me to see that strlen receives a corrupted pointer, see below.

#include <QApplication>
#include <QMessageBox>

void func(void *, void *, void *, void *)  {}

struct Gui
{
  QApplication qApplication;
  Gui(int argc, char ** argv) : qApplication(argc, argv)  {}
};

struct Process
{
  Process(const std::string &, int argc, char ** argv) {
    func(ptr(), ptr(), ptr(), ptr());
    std::string recent;
    std::string path = std::string("Hi!");
    recent           = std::string("Hi!");
    m_message        = std::string("Hi!");
    m_gui = new Gui(argc, argv);
  }
  ~Process()  { delete m_gui; }

  int exec(void) {
    return QMessageBox::warning(0, "Exit", "Sure?", QMessageBox::Ok);
  }

  void * ptr(void)  { return 0; }

  Gui       * m_gui;
  std::string m_message;
};

std::size_t strlen(const char * p) {
  std::size_t s = 0;
  while (*p++)
    s++;
  return s;
}

int main(int argc, char ** argv) {
  Process process("SomeString", argc, argv);
  return process.exec();
}

Crash backtrace:

#0  0x0000000000400f13 in strlen (p=0x11 <Address 0x11 out of bounds>) at /home/alex/test/megaCrash/myprog.cpp:39
#1  0x0000003880a41922 in XSetCommand () from /usr/lib64/libX11.so.6
#2  0x0000003880a45fa6 in XSetWMProperties () from /usr/lib64/libX11.so.6
#3  0x00002aaaaad2e5ea in QWidgetPrivate::create_sys(unsigned long, bool, bool) () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#4  0x00002aaaaace735d in QWidget::create(unsigned long, bool, bool) () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#5  0x00002aaaaacef73a in QWidget::setVisible(bool) () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#6  0x00002aaaab11de5e in QDialog::setVisible(bool) () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#7  0x00002aaaab11d9e6 in QDialog::exec() () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#8  0x00002aaaab13bb40 in ?? () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#9  0x00002aaaab13bc7f in QMessageBox::warning(QWidget*, QString const&, QString const&, QFlags<QMessageBox::StandardButton>, QMessageBox::StandardButton) () from /usr/local/Trolltech/Qt-4.7.2/lib/libQtGui.so.4
#10 0x0000000000401514 in Process::exec (this=0x7fffffffe4e0) at /home/alex/test/megaCrash/myprog.cpp:27
#11 0x0000000000400fb6 in main (argc=1, argv=0x7fffffffe5f8) at /home/alex/test/megaCrash/myprog.cpp:47

As you see it happens in strlen. And that's why I included my own implementation for it. Its argument p points to nowhere. I tried to reproduce it with debug build of Qt - no luck. This all makes me think that there is a nasty memory corruption here. But where could it happen? I do only innocent things here.

I use CMake to build it:

cmake_minimum_required (VERSION 2.8) 

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-local-typedefs -fpic -fvisibility=hidden -m64")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb -DDEBUG -gdwarf-2 -fstack-protector-all")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

find_package(Qt4 REQUIRED)
include(${QT_USE_FILE})

add_executable(myprog myprog.cpp)

target_link_libraries(myprog ${QT_LIBRARIES})

I tried to find hints in Qt documentation and the Internet - no luck. Thank you

Was it helpful?

Solution

QApplication has a special (and IMHO questionable) requirement for argc and argv. See the documentation:

Warning: The data referred to by argc and argv must stay valid for the entire lifetime of the QApplication object. In addition, argc must be greater than zero and argv must contain at least one valid character string.

If argc and argv get destroyed during runtime, undefined behavior occurs. It may work on some platforms and it will crash on others. Change your code accordingly and check if it fixes your problem.

OTHER TIPS

I encountered the same problem and implemented the following class to persist the command line parameters:

.h:

#pragma once

#include <string>
#include <vector>

using std::string;
using std::vector;

class PersistentArgs
{
protected:
    vector<string> mArgStrs;

public:
    int mArgc;
    vector<char*> mArgv;

    PersistentArgs() = delete;
    PersistentArgs(int argc, char* argv[]);
    virtual ~PersistentArgs();
};

.cpp:

#include "PersistentArgs.h"

PersistentArgs::PersistentArgs(int argc, char* argv[])
{
    mArgc = argc;

    for (int i = 0;  i < argc;  i++)
    {
        string arg(argv[i]);
        mArgStrs.push_back (arg);
    }

    for (int i = 0;  i < argc;  i++)
    {
        mArgv.push_back ((char*)mArgStrs[i].c_str());
    }

    mArgv.push_back (nullptr);
}

PersistentArgs::~PersistentArgs()
{
    mArgv.clear();
    mArgStrs.clear();
}

usage:


PersistentArgs* args;


void atStart (int argc, char* argv[])
{
    args = new PersistentArgs (argc, argv);
    QApplication* qtApp = new QApplication (args->mArgc, &args->mArgv[0]);

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top