Skip to content

Commit

Permalink
Bugfix/3169 stack fix (#3182)
Browse files Browse the repository at this point in the history
* reffs #3169 initial new stack handling

* refs #3169 progress on unified thread and exception stack trace support

* reffs #3169 removed lots of old code related to the old optional call stack implementation; the HAVE_RUNTIME_THREAD_STACK_TRACE constant is always True, removed associated build options and internal logic

* refs #3169 fixed deadlock in thread stack retrieval

* refs #3169 new stack trace API updates

* refs #3177 fixed binary module installation with autotools

* refs #3179 std::string COW issue workaround (#3180)

* reffs #3169 removed lots of old code related to the old optional call stack implementation; the HAVE_RUNTIME_THREAD_STACK_TRACE constant is always True, removed associated build options and internal logic

* refs #3169 new stack trace API updates

* refs #3169 finalized the API and fixed C++ issues

* refs #3169 refactored default exception handling & warning output, added language info to exceptions, updates tests and docs

* refs #3169 fixed test

* refs #3169 more API updates

* refs #3169 fixed dbg stmt

* refs #3169 show builtin code location properly in call & exception stacks
  • Loading branch information
davidnich authored and sejvlond committed Dec 14, 2018
1 parent cfaaba8 commit 64d3a5f
Show file tree
Hide file tree
Showing 32 changed files with 1,784 additions and 1,459 deletions.
9 changes: 0 additions & 9 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ option(ICONV_TRANSLIT
"Force //Translit to iconv encoding to do transliteration, if OFF it is tested for"
OFF)

option(QORE_RUNTIME_THREAD_STACK_TRACE
"enable runtime thread stack trace (turning off breaks compatibility)"
ON)

set(VERSION_MAJOR 0)
set(VERSION_MINOR 9)
set(VERSION_SUB 0)
Expand Down Expand Up @@ -37,10 +33,6 @@ else ()
add_definitions(-DNDEBUG)
endif ()

#if ((NOT ${QORE_BUILD_TYPE_LWR} MATCHES "debug") AND QORE_RUNTIME_THREAD_STACK_TRACE)
# message(FATAL_ERROR "QORE_RUNTIME_THREAD_STACK_TRACE only available on debug builds")
#endif()

# simulate QoreConfig
set(QORE_QDX_EXECUTABLE "${CMAKE_SOURCE_DIR}/doxygen/qdx")
# simulate QoreConfig
Expand Down Expand Up @@ -491,7 +483,6 @@ set(LIBQORE_CPP_SRC
lib/QoreSQLStatement.cpp
lib/ExecArgList.cpp
lib/CallReferenceNode.cpp
lib/CallStack.cpp
lib/NamedScope.cpp
lib/RWLock.cpp
lib/QoreSSLBase.cpp
Expand Down
15 changes: 0 additions & 15 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1308,20 +1308,6 @@ if test "$enable_optimization" = "auto"; then
fi
fi

AC_ARG_ENABLE([runtime-thread-stack-trace],
[AS_HELP_STRING([--enable-runtime-thread-stack-trace],
[enable runtime thread stack trace (performance penalty, default: off)])],
[case "${enable_runtime_thread_stack_trace}" in
yes|no) ;;
*) AC_MSG_ERROR(bad value ${enable_runtime_thread_stack_trace} for --enable-runtime-thread-stack-trace) ;;
esac],
[enable_runtime_thread_stack_trace=yes])

if test "${enable_runtime_thread_stack_trace}" = "yes" -o "${enable_debug}" = yes; then
AC_DEFINE(QORE_RUNTIME_THREAD_STACK_TRACE, 1, [to enable runtime thread stack tracing, needed for getAllThreadCallStacks()])
enable_runtime_thread_stack_trace=yes
fi

# check for gcc visibility support
AC_MSG_CHECKING([for gcc visibility support])
if test "$GXX" = "yes"; then
Expand Down Expand Up @@ -1878,7 +1864,6 @@ AM_CONDITIONAL([COND_PROFILE], [test "$enable_profile" = yes])
AM_CONDITIONAL([COND_SINGLE_COMPILATION_UNIT], [test "$enable_single_compilation_unit" = yes])
AM_CONDITIONAL([COND_MACOSX], [test "$darwin" = yes])
AM_CONDITIONAL([COND_DOXYGEN], [test -n "$with_doxygen"])
AM_CONDITIONAL([COND_STACK_TRACE], [test "$enable_runtime_thread_stack_trace" = yes])
AM_CONDITIONAL([COND_SOLARIS_CC_X86_64], [test "$solaris_cc_x86_64" = yes])
AM_CONDITIONAL([COND_SOLARIS_CC_I386], [test "$solaris_cc_i386" = yes])
AM_CONDITIONAL([COND_SOLARIS_CC_SPARC32], [test "$solaris_cc_sparc32" = yes])
Expand Down
15 changes: 14 additions & 1 deletion doxygen/lang/900_release_notes.dox.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,20 @@
- @ref Qore::set_default_thread_stack_size() "set_default_thread_stack_size()"
- @ref Qore::set_module_option() "set_module_option()"
- @ref Qore::set_thread_name() "set_thread_name()"
- Updated functions:
- @ref Qore::get_ex_pos() "get_ex_pos()": \c lang info was added to the result string if available
- New modules:
- <a href="../../modules/FsUtil/html/index.html">FsUtil</a>
- <a href="../../modules/Logger/html/index.html">Logger</a>
- <a href="../../modules/reflection/html/index.html">reflection</a>
- New and updated hashdecls:
- @ref Qore::NetIfInfo "NetIfInfo": new @ref hashdecl "hashdecl" for the @ref Qore::get_netif_list() "get_netif_list()" function
- @ref Qore::CallStackInfo "CallStackInfo": updated with new members: \c programid and \c statementid
- @ref Qore::CallStackInfo "CallStackInfo": updated with new members:
- \c lang
- \c programid
- \c statementid
- @ref Qore::ExceptionInfo "ExceptionInfo": updated with a new member:
- \c lang
- New constants:
- @ref Qore::DomainCodeMap "DomainCodeMap"
- @ref Qore::DomainStringMap "DomainStringMap"
Expand Down Expand Up @@ -171,6 +178,8 @@
- Updated \c parse_to_qore_value() to support single-element lists and hashes with curly brackets including
empty hashes
(<a href="https://github.com/qorelanguage/qore/issues/3138">issue 3138</a>)
- updated @ref Util::get_exception_string() "get_exception_string()" to show the \c lang value
(<a href="https://github.com/qorelanguage/qore/issues/3182">issue 3182</a>)
- <a href="../../modules/CsvUtil/html/index.html">CsvUtil</a> module updates:
- Added public methods \c AbstractCsvIterator::getRawLine() and \c AbstractCsvIterator::getRawLineValues() (<a href="https://github.com/qorelanguage/qore/issues/2739">issue 2739</a>)
- <a href="../../modules/Swagger/html/index.html">Swagger</a>:
Expand All @@ -187,6 +196,10 @@
- <a href="../../modules/DebugHandler/html/index.html">DebugHandler</a> reimplemented to support multiple websocket handlers
- Programs are not interrupted in bootstrap code
- Command line utils display source line code when interrupted
- Runtime thread stack traces are available in all builds and the
@ref Qore::Option::HAVE_RUNTIME_THREAD_STACK_TRACE "HAVE_RUNTIME_THREAD_STACK_TRACE" constant is always
@ref True "True". Furthermore, the %Qore library has been extended to support stack tracing when embedding
or integrating code in other programming languages at runtime

@subsection qore_09_bug_fixes Bug Fixes in Qore
- worked around a potential COW bug in \c std::string in GNU libdstdc++ 6+
Expand Down
31 changes: 31 additions & 0 deletions examples/test/qlib/Util/get_exception_string.qtest
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

%requires ../../../../qlib/Util.qm
%requires ../../../../qlib/QUnit.qm

%exec-class GetExceptionString

public class GetExceptionString inherits QUnit::Test {
constructor() : Test("GetExceptionString", "1.0") {
addTestCase("get_exception_string()", \testGetExceptionString());

set_return_value(main());
}

testGetExceptionString() {
hash<ExceptionInfo> ex;
try {
throw "ERR", "err";
} catch (hash<ExceptionInfo> ex1) {
ex = ex1;
}
assertEq("Qore", ex.callstack[0].lang);
assertEq("GetExceptionString::constructor", ex.callstack.last().function);
}
}
9 changes: 6 additions & 3 deletions examples/test/qore/classes/Program/program-vars.qtest
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
%require-types
%strict-args
%no-child-restrictions
%no-debugging
%no-debugging

%requires QUnit

Expand Down Expand Up @@ -58,7 +58,7 @@ class ProgramVarsTest inherits QUnit::Test {
"endline": 1,
"source": "",
"offset": 0,
"callstack": new list<hash<CallStackInfo>>(),
"lang": "Qore",
"err": 1,
)),
),
Expand All @@ -67,7 +67,10 @@ class ProgramVarsTest inherits QUnit::Test {
"value": NOTHING,
),
);
assertEq(vh, p.callFunction("test3"));
auto v = p.callFunction("test3");
# remove the call stack
v.ex.value -= "callstack";
assertEq(vh, v);
}
}
}
32 changes: 32 additions & 0 deletions examples/test/qore/functions/get_ex_pos.qtest
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

%requires ../../../../qlib/QUnit.qm

%exec-class GetExPosTest

public class GetExPosTest inherits QUnit::Test {
constructor() : Test("GetExPosTest", "1.0") {
addTestCase("get_ex_pos() test", \getExPosTest());

# Return for compatibility with test harness that checks return value.
set_return_value(main());
}

getExPosTest() {
try {
if (True) {
throw "ERR", "desc";
}
assertTrue(False);
} catch (hash<ExceptionInfo> ex) {
string str = get_ex_pos(ex);
assertRegex("get_ex_pos.qtest:24 \\(Qore\\)$", str);
}
}
}
95 changes: 15 additions & 80 deletions examples/test/qore/misc/exception.qtest
Original file line number Diff line number Diff line change
Expand Up @@ -12,62 +12,42 @@

class ExceptionTest inherits QUnit::Test {
private {
string err;
string err2;
string err3;
string desc;
string arg;
string type;
hash<ExceptionInfo> ex;
}

constructor() : QUnit::Test("Exception test", "1.0") {
addTestCase("Test simple try/catch block", \testSimpleTryCatch());
addTestCase("Test rethrow", \testRethrow());
addTestCase("misc tests", \miscTests());
#addTestCase("Complex try/catch hierarchy", \testComplexHierarchy());
set_return_value(main());
}

setUp() {
err = '';
err2 = '';
err3 = '';
desc = '';
arg = '';
type = '';
}

testSimpleTryCatch() {
try {
throw "testing", "123", "test";
} catch (hash<ExceptionInfo> ex1) {
ex = ex1;
}
catch (ex) {
err = ex.err;
desc = ex.desc;
arg = ex.arg;
}
assertEq("testing", err);
assertEq("123", desc);
assertEq("test", arg);
assertEq("testing", ex.err);
assertEq("123", ex.desc);
assertEq("test", ex.arg);
assertEq("Qore", ex.lang);
}

testRethrow() {
try {
try {
throw "TEST-ERROR", "this is a test";
}
catch () {
} catch () {
rethrow;
}
} catch (hash<ExceptionInfo> ex1) {
ex = ex1;
}
catch (ex) {
err = ex.err;
desc = ex.desc;
type = ex.type;
}
assertEq("TEST-ERROR", err);
assertEq("this is a test", desc);
assertEq("User", type);
assertEq("TEST-ERROR", ex.err);
assertEq("this is a test", ex.desc);
assertEq("User", ex.type);
assertEq("Qore", ex.lang);
}

miscTests() {
Expand All @@ -77,53 +57,8 @@ class ExceptionTest inherits QUnit::Test {
int a = 1;
try {
throw a;
}
catch (hash<ExceptionInfo> ex) {
} catch (hash<ExceptionInfo> ex) {
assertEq(1, ex.err);
}
}

/*testComplexHierarchy() {
try {
try {
try {
printf("%s\n", snope.refresh());
}
catch (ex) {
err = ex.err;

try {
try {
context gee (gee) where (%foo == "gee")
printf("%s\n", sdfdas);
}
catch (ex1) {
desc = shift argv;
printf("QORE %s Exception in line %d of file %s: %s: %s\n",
ex1.type, ex1.line, ex1.file, ex1.err, ex1.desc);
throw snope.blah();
}
throw snope.sdfds();
}
catch (ex2) {
err2 = ex2.err;
throw "TEST";
}
}
}
catch (ex) {
err3 = ex.err;
}
}
catch (ex) {
printf("QORE %s Exception in line %d of file %s: %s: %s\n",
ex.type, ex.line, ex.file, ex.err, ex.desc);
context (gee) where (%whiz == "wdsf")
printf("%s\n", %dsfdf);
}

assertEq("PSEUDO-METHOD-DOES-NOT-EXIST", err);
assertEq("PSEUDO-METHOD-DOES-NOT-EXIST", err2);
assertEq("TEST", err3);
}*/
}
2 changes: 1 addition & 1 deletion examples/test/qore/misc/has_effect.qtest
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class HasEffectTest inherits QUnit::Test {
assertEq(NOTHING, parse_result);
if (testBackground) {
Program p3(PO_NEW_STYLE|PO_ALLOW_STATEMENT_NO_EFFECT);
*hash parse_result = p3.parse("background " + statements, "");
parse_result = p3.parse("background " + statements, "");
assertEq(NOTHING, parse_result);
}
}
Expand Down
8 changes: 5 additions & 3 deletions examples/test/qore/stack/get-call-stack.qtest
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ class GetCallThreadTest inherits QUnit::Test {
set_return_value(main());
}

any f2(bool all) {
auto f2(bool all) {
return all ? get_all_thread_call_stacks() : get_thread_call_stack();
}
any f1(bool all) {

auto f1(bool all) {
return f2(all);
}

testGetCallThread() {
hash h = f1(True);
hash<auto> h = f1(True);
testAssertionValue("get_all_thread_call_stacks-0", h{gettid()}[0].function, "get_all_thread_call_stacks");
testAssertionValue("get_all_thread_call_stacks-1", h{gettid()}[1].function, "GetCallThreadTest::f2");
testAssertionValue("get_all_thread_call_stacks-2", h{gettid()}[2].function, "GetCallThreadTest::f1");
Expand Down
Loading

0 comments on commit 64d3a5f

Please sign in to comment.