8

昨日、私は悲惨な目に遭い、24 時間もフラストレーションを感じていました。問題は、ランダムに発生する予期しないクラッシュに要約されました。さらに複雑なことに、デバッグ レポートにも完全にランダムなパターンがありました。さらに複雑なことに、すべてのデバッグ トレースがランダムなQt ソースまたはネイティブ DLL のいずれかにつながっていました。

以下に、素敵なレポートの例をいくつか示します。

Program received signal SIGSEGV, Segmentation fault.
0x0000000077864324 in ntdll!RtlAppendStringToString () from C:\Windows\system32\ntdll.dll
(gdb) bt
#0 0x0000000077864324 in ntdll!RtlAppendStringToString () from C:\Windows\system32\ntdll.dll
#1 0x000000002efc0230 in ?? ()
#2 0x0000000002070005 in ?? ()
#3 0x000000002efc0000 in ?? ()
#4 0x000000007787969f in ntdll!RtlIsValidHandle () from C:\Windows\system32\ntdll.dll
#5 0x0000000000000000 in ?? ()

warning: HEAP: Free Heap block 307e5950 modified at 307e59c0 after it was freed
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000778bf0b2 in ntdll!ExpInterlockedPopEntrySListFault16 () from C:\Windows\system32\ntdll.dll
(gdb) bt
#0 0x00000000778bf0b2 in ntdll!ExpInterlockedPopEntrySListFault16 () from C:\Windows\system32\ntdll.dll
#1 0x000000007786fd34 in ntdll!RtlIsValidHandle () from C:\Windows\system32\ntdll.dll
#2 0x0000000077910d20 in ntdll!RtlGetLastNtStatus () from C:\Windows\system32\ntdll.dll
#3 0x00000000307e5950 in ?? ()
#4 0x00000000307e59c0 in ?? ()
#5 0x00000000ffffffff in ?? ()
#6 0x0000000000220f10 in ?? ()
#7 0x0000000077712d60 in WaitForMultipleObjectsEx () from C:\Windows\system32\kernel32.dll
#8 0x0000000000000000 in ?? ()

Program received signal SIGSEGV, Segmentation fault.
0x0000000000a9678a in QBasicAtomicInt::ref (this=0x8) at ../../include/QtCore/../../../qt-src/src/corelib/arch/qatomic_x86_64.h:121
121 : "memory");
(gdb) bt
#0 0x0000000000a9678a in QBasicAtomicInt::ref (this=0x8) at ../../include/QtCore/../../../qt-src/src/corelib/arch/qatomic_x86_64.h:121
#1 0x00000000009df08e in QVariant::QVariant (this=0x21e4d0, p=...) at d:/Distributions/qt-src/src/corelib/kernel/qvariant.cpp:1426
#2 0x0000000000b4dde9 in QList<QVariant>::value (this=0x323bd480, i=1) at ../../include/QtCore/../../../qt-src/src/corelib/tools/qlist.h:666
#3 0x00000000009ccff7 in QObject::property (this=0x3067e900,
name=0xa9d042a <QCDEStyle::drawPrimitive(QStyle::PrimitiveElement, QStyleOption const*, QPainter*, QWidget const*) const::pts5+650> "_q_stylerect")
at d:/Distributions/qt-src/src/corelib/kernel/qobject.cpp:3742
#4 0x0000000000000000 in ?? ()

ご覧のとおり、これは非常に厄介なものであり、有用な情報はありません。ただ、一つ気になった点がありました。これはコンパイル中の奇妙な警告であり、目で捉えるのも困難です。

In file included from d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer.h:50:0,
                 from d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/QSharedPointer:1,
                 from ../../../../source/libraries/Project/sources/Method.hpp:4,
                 from ../../../../source/libraries/Project/sources/Slot.hpp:4,
                 from ../../../../source/libraries/Project/sources/Slot.cpp:1:
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h: In instantiation of 'static void QtSharedPointer::ExternalRefCount<T>::deref(QtSharedPointer::ExternalRefCount<T>::Data*, T*) [with T = Project::Method::Private; QtSharedPointer::ExternalRefCount<T>::Data = QtSharedPointer::ExternalRefCountData]':
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h:336:11:   required from 'void QtSharedPointer::ExternalRefCount<T>::deref() [with T = Project::Method::Private]'
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h:401:38:   required from 'QtSharedPointer::ExternalRefCount<T>::~ExternalRefCount() [with T = Project::Method::Private]'
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h:466:7:   required from here
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h:342:21: warning: possible problem detected in invocation of delete operator: [enabled by default]
d:/Libraries/x64/MinGW-w64/4.7.2/Qt/4.8.4/include/QtCore/qsharedpointer_impl.h:337:28: warning: 'value' has incomplete type [enabled by default]

実際、私は最後の手段としてのみこの警告に目を向けました。なぜなら、バグを見つけるための必死の追跡において、コードはすでに文字通りログに感染していたからです。

それを注意深く読んだ後、たとえば、std::unique_ptrまたはstd::scoped_ptrfor Pimplを使用する場合、確実にデストラクターを提供する必要があることを思い出しました。そうしないと、コードはコンパイルさえしません。std::shared_ptrただし、デストラクタを気にせず、それがなくても問題なく動作することも覚えています。この奇妙な警告に注意を払わなかったもう 1 つの理由がこれでした。簡単に言えば、デストラクタを追加すると、このランダムなクラッシュが停止しました。QSharedPointerに比べて、Qtにはいくつかの設計上の欠陥があるようstd::shared_ptrです。Qt 開発者がこの警告エラーに変換した方がよいと思います。なぜなら、このようなマラソンのデバッグは、時間、労力、および神経に値するものではないからです。

私の質問は次のとおりです。

  1. 何が問題なのQSharedPointerですか? なぜデストラクタは非常に重要なのですか?
  2. デストラクタがないのにクラッシュしたのはなぜですか? これらのオブジェクト ( Pimpl +を使用しているQSharedPointer) はスタック上に作成され、他のオブジェクトはそれらの死後にそれらにアクセスできなくなります。しかし、クラッシュは彼らの死後、ランダムな期間に発生しました。
  3. 誰もそのような問題に遭遇したことがありますか? あなたの経験を共有してください。
  4. Qt にそのような他の落とし穴がありますか?

願わくば、これらの質問と私の投稿全般が、私が過去 24 時間にわたって経験した地獄を他の人が回避するのに役立つことを願っています。

4

2 に答える 2

3

この問題は Qt 5 で回避されました。https://codereview.qt-project.org/#change,26974を参照してください。

コンパイラが間違ったデストラクタを呼び出したり、別のメモリ レイアウトを想定したりすると、何らかのメモリ破損が発生する可能性があります。コンパイラは、この問題に対して警告ではなくエラーを出す必要があると思います。

于 2013-03-18T07:31:27.227 に答える
1

で同様の問題がstd::unique_ptr発生します。不完全な型で使用すると、破壊されたデストラクタも発生する可能性があります。もちろん、修正は非常に簡単です。クラスのコンストラクターを宣言し、実装ファイルで次のように定義します。

MyClass::~MyClass() = default;

std::unique_ptrこれが問題である理由はstd::shared_ptr、デストラクタが前者の型の一部であるが、後者のメンバーであるためです。

于 2015-11-03T13:54:04.503 に答える