Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Ошибка сегментации при создании Qt QApplication с новым

Автор вопроса: Bush WalkerОтветов: 2

У меня есть программа, в которой QApplication создается с новым оператором. Вылетает по неизвестной причине. Я использую RedHat Linux, G++ 4.8.2, Qt 4.7.2, которые были собраны с помощью того же компилятора.

Этот исходный код содержит много бесполезных, но безобидных фрагментов, например, функцию func с четырьмя неиспользуемыми аргументами. Если я попытаюсь удалить их и еще немного упростить программу, сбой больше не будет воспроизводиться, что, конечно, не означает, что проблема решена.

Сбой происходит в функции strlen, которая вызывается из системной функции XSetCommand. Добавление моей собственной простой реализации позволило мне увидеть, что strlen получает поврежденный указатель, см. ниже.

#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();
}

Отслеживание сбоя:

#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

Как видите, это происходит в strlen. И именно поэтому я включил для него собственную реализацию. Его аргумент p указывает в никуда. Я попытался воспроизвести его с помощью отладочной сборки Qt - безуспешно. Все это заставляет меня думать, что здесь есть неприятная порча памяти. Но где это могло произойти? Я делаю здесь только невинные вещи.

Я использую CMake для его сборки:

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})

Я пытался найти подсказки в документации Qt и в Интернете - безуспешно. Спасибо

  • Я скопировал ваш код, и он работает в реальном режиме, но вылетает в режиме отладки. Я использую Qt 4.6.2, CentOS 6.2 x64 hank 07.03.2014
  • Вы читали ошибки / трассировку стека? Не могли бы вы показать свой код, где вы называете свой strlen? Почему вы не проверяете p != 0 в своем strlen? Dmitry Sazonov 07.03.2014
  • Дмитрий, обратка чуть выше. Я не вызываю strlen. Это делает системная функция XSetCommand. Я просто заменил системный strlen на свой, чтобы проверить, что там передается. Изначально в программе не было strlen и вылет был. Как следует из вышеизложенного, XSetCommand передает поврежденный указатель (p=0x11). Так что проверка p!=0 здесь бесполезна. Опять же, мой strlen здесь только для целей отладки. Спасибо Bush Walker 07.03.2014
  • Хэнк, здорово, что это воспроизводимо не только у меня. Спасибо. Bush Walker 07.03.2014

linuxqtnew-operatorsegmentation-faultqapplication

Ответы

Ответ 1 · рейтинг 18 · scai

QApplication имеет особое (и ИМХО сомнительное) требование для argc и argv. См. документацию:

Внимание! Данные, на которые ссылаются argc и argv, должны оставаться действительными в течение всего времени существования объекта QApplication. Кроме того, argc должен быть больше нуля, а argv должен содержать хотя бы одну допустимую строку символов.

Если argc и argv уничтожаются во время выполнения, возникает неопределенное поведение. Он может работать на одних платформах и давать сбои на других. Измените свой код соответствующим образом и проверьте, решает ли он вашу проблему.

Ответ 2 · Den-Jason

Я столкнулся с той же проблемой и реализовал следующий класс для сохранения параметров командной строки:

.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();
}

использование:


PersistentArgs* args;


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

}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы