aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2013-07-09 13:42:09 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-07-10 13:02:01 +0200
commit5706bda12306130c187d7fa1b7767ede0be34c84 (patch)
treeb744528aeb6858048cdc9143eb31bdaa1449a1ad /src
parentce3767f3716bbc92a31b2008dc749f4840c23718 (diff)
Fix rare crashes in release builds on Windows with exceptions
When throwing exceptions we have a tendency to save a backtrace, using StackWalk64 on Windows. Before we can do that stack walk, we have to capture the current processor register state, in particular the frame pointer, for which we call RtlCaptureContext. Almost naturally that function requires the caller to have set up a stack frame, which may not have happened when compiling with release flags. As a remedy, this patch moves the code that calls RtlCaptureContext into a separate file, which will be compiled with frame pointer optimizations disabled. Change-Id: I3ce53b47c4a421efeaa3e575429d85327540ca97 Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/qml/qml/v4/qv4engine.cpp111
-rw-r--r--src/qml/qml/v4/qv4stacktrace.cpp159
-rw-r--r--src/qml/qml/v4/qv4stacktrace_p.h75
-rw-r--r--src/qml/qml/v4/v4.pri6
4 files changed, 241 insertions, 110 deletions
diff --git a/src/qml/qml/v4/qv4engine.cpp b/src/qml/qml/v4/qv4engine.cpp
index 343e24f1bf..2f40442928 100644
--- a/src/qml/qml/v4/qv4engine.cpp
+++ b/src/qml/qml/v4/qv4engine.cpp
@@ -65,15 +65,7 @@
#include "qv4sequenceobject_p.h"
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
-
-#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MAC)
-#define HAVE_GNU_BACKTRACE
-#include <execinfo.h>
-#endif
-
-#if defined(Q_OS_WIN)
-#include <DbgHelp.h>
-#endif
+#include "qv4stacktrace_p.h"
#ifdef V4_ENABLE_JIT
# include "qv4isel_masm_p.h"
@@ -589,106 +581,9 @@ Object *ExecutionEngine::qmlContextObject() const
}
namespace {
- struct NativeFrame {
- Function *function;
- int line;
- };
-
- struct NativeStackTrace
- {
- void *trace[100];
- int nativeFrameCount;
- int currentNativeFrame;
- ExecutionEngine *engine;
-
- NativeStackTrace(ExecutionContext *context)
- {
- engine = context->engine;
- currentNativeFrame = 0;
-
-#if defined(HAVE_GNU_BACKTRACE)
- UnwindHelper::prepareForUnwind(context);
-
- nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
-#elif defined(Q_OS_WIN)
-
- int machineType = 0;
-
- CONTEXT winContext;
- memset(&winContext, 0, sizeof(winContext));
- winContext.ContextFlags = CONTEXT_FULL;
- RtlCaptureContext(&winContext);
-
- STACKFRAME64 sf64;
- memset(&sf64, 0, sizeof(sf64));
-
-#if defined(Q_PROCESSOR_X86_32)
- machineType = IMAGE_FILE_MACHINE_I386;
-
- sf64.AddrFrame.Offset = winContext.Ebp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Eip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Esp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#elif defined(Q_PROCESSOR_X86_64)
- machineType = IMAGE_FILE_MACHINE_AMD64;
-
- sf64.AddrFrame.Offset = winContext.Rbp;
- sf64.AddrFrame.Mode = AddrModeFlat;
- sf64.AddrPC.Offset = winContext.Rip;
- sf64.AddrPC.Mode = AddrModeFlat;
- sf64.AddrStack.Offset = winContext.Rsp;
- sf64.AddrStack.Mode = AddrModeFlat;
-
-#else
-#error "Platform unsupported!"
-#endif
-
- nativeFrameCount = 0;
-
- while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
-
- if (sf64.AddrReturn.Offset == 0)
- break;
-
- trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
- nativeFrameCount++;
- if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
- break;
- }
-
-#else
- nativeFrameCount = 0;
-#endif
- }
-
- NativeFrame nextFrame() {
- NativeFrame frame;
- frame.function = 0;
- frame.line = -1;
-
- for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
- quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
- // The pointers from the back trace point to the return address, but we are interested in
- // the caller site.
- pc = pc - 1;
-
- Function *f = engine->functionForProgramCounter(pc);
- if (!f)
- continue;
-
- frame.function = f;
- frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code));
- }
-
- return frame;
- }
- };
struct LineNumberResolver {
const ExecutionEngine* engine;
- QScopedPointer<NativeStackTrace> nativeTrace;
+ QScopedPointer<QV4::NativeStackTrace> nativeTrace;
LineNumberResolver(const ExecutionEngine *engine)
: engine(engine)
@@ -702,7 +597,7 @@ namespace {
frame->line = function->lineNumberForProgramCounter(offset);
} else {
if (!nativeTrace)
- nativeTrace.reset(new NativeStackTrace(engine->current));
+ nativeTrace.reset(new QV4::NativeStackTrace(engine->current));
NativeFrame nativeFrame = nativeTrace->nextFrame();
if (nativeFrame.function == function)
diff --git a/src/qml/qml/v4/qv4stacktrace.cpp b/src/qml/qml/v4/qv4stacktrace.cpp
new file mode 100644
index 0000000000..a96824e420
--- /dev/null
+++ b/src/qml/qml/v4/qv4stacktrace.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <DbgHelp.h>
+#endif
+
+#include "qv4stacktrace_p.h"
+#include "qv4function_p.h"
+#include "qv4engine_p.h"
+#include "qv4unwindhelper_p.h"
+
+#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MAC)
+#define HAVE_GNU_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#if defined(Q_OS_WIN)
+// We call RtlCaptureContext and that will crash if the compiler did not
+// create a stack frame for the function that calls RtlCaptureContext.
+#if defined(Q_CC_MSVC)
+#pragma optimize( "y", off )
+#elif defined(Q_CC_GNU)
+#pragma GCC optimize ("O0")
+#else
+#error "Don't know how to disable frame pointer optimizations with this compiler on Windows!"
+#endif
+
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+NativeStackTrace::NativeStackTrace(ExecutionContext *context)
+{
+ engine = context->engine;
+ currentNativeFrame = 0;
+
+#if defined(HAVE_GNU_BACKTRACE)
+ UnwindHelper::prepareForUnwind(context);
+
+ nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
+#elif defined(Q_OS_WIN)
+
+ int machineType = 0;
+
+ CONTEXT winContext;
+ memset(&winContext, 0, sizeof(winContext));
+ winContext.ContextFlags = CONTEXT_FULL;
+ RtlCaptureContext(&winContext);
+
+ STACKFRAME64 sf64;
+ memset(&sf64, 0, sizeof(sf64));
+
+#if defined(Q_PROCESSOR_X86_32)
+ machineType = IMAGE_FILE_MACHINE_I386;
+
+ sf64.AddrFrame.Offset = winContext.Ebp;
+ sf64.AddrFrame.Mode = AddrModeFlat;
+ sf64.AddrPC.Offset = winContext.Eip;
+ sf64.AddrPC.Mode = AddrModeFlat;
+ sf64.AddrStack.Offset = winContext.Esp;
+ sf64.AddrStack.Mode = AddrModeFlat;
+
+#elif defined(Q_PROCESSOR_X86_64)
+ machineType = IMAGE_FILE_MACHINE_AMD64;
+
+ sf64.AddrFrame.Offset = winContext.Rbp;
+ sf64.AddrFrame.Mode = AddrModeFlat;
+ sf64.AddrPC.Offset = winContext.Rip;
+ sf64.AddrPC.Mode = AddrModeFlat;
+ sf64.AddrStack.Offset = winContext.Rsp;
+ sf64.AddrStack.Mode = AddrModeFlat;
+
+#else
+#error "Platform unsupported!"
+#endif
+
+ nativeFrameCount = 0;
+
+ while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
+
+ if (sf64.AddrReturn.Offset == 0)
+ break;
+
+ trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
+ nativeFrameCount++;
+ if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
+ break;
+ }
+
+#else
+ nativeFrameCount = 0;
+#endif
+ }
+
+NativeFrame NativeStackTrace::nextFrame() {
+ NativeFrame frame;
+ frame.function = 0;
+ frame.line = -1;
+
+ for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
+ quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
+ // The pointers from the back trace point to the return address, but we are interested in
+ // the caller site.
+ pc = pc - 1;
+
+ Function *f = engine->functionForProgramCounter(pc);
+ if (!f)
+ continue;
+
+ frame.function = f;
+ frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code));
+ }
+
+ return frame;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4stacktrace_p.h b/src/qml/qml/v4/qv4stacktrace_p.h
new file mode 100644
index 0000000000..79cb4d1813
--- /dev/null
+++ b/src/qml/qml/v4/qv4stacktrace_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STACKTRACE_P_H
+#define QV4STACKTRACE_P_H
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+struct ExecutionEngine;
+struct ExecutionContext;
+
+struct NativeFrame {
+ Function *function;
+ int line;
+};
+
+struct NativeStackTrace
+{
+ void *trace[100];
+ int nativeFrameCount;
+ int currentNativeFrame;
+ ExecutionEngine *engine;
+
+ NativeStackTrace(ExecutionContext *context);
+
+ NativeFrame nextFrame();
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4STACKTRACE_P_H
diff --git a/src/qml/qml/v4/v4.pri b/src/qml/qml/v4/v4.pri
index 46b4770f02..48d9e82cb5 100644
--- a/src/qml/qml/v4/v4.pri
+++ b/src/qml/qml/v4/v4.pri
@@ -56,7 +56,8 @@ SOURCES += \
$$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
- $$PWD/qv4qmlextensions.cpp
+ $$PWD/qv4qmlextensions.cpp \
+ $$PWD/qv4stacktrace.cpp
HEADERS += \
$$PWD/qv4global_p.h \
@@ -111,7 +112,8 @@ HEADERS += \
$$PWD/qv4sequenceobject_p.h \
$$PWD/qv4include_p.h \
$$PWD/qv4qobjectwrapper_p.h \
- $$PWD/qv4qmlextensions_p.h
+ $$PWD/qv4qmlextensions_p.h \
+ $$PWD/qv4stacktrace_p.h
llvm-libs {