Skip to content

Commit b6855e3

Browse files
committed
Cleanup stack parsing / demangling
Fixes #596
1 parent 327d057 commit b6855e3

File tree

3 files changed

+41
-6
lines changed

3 files changed

+41
-6
lines changed

inst/unitTests/cpp/exceptions.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ double takeLogRcpp(double val) {
3838
return log(val);
3939
}
4040

41+
// [[Rcpp::export]]
42+
double takeLogStop(double val) {
43+
if (val <= 0.0) {
44+
Rcpp::stop("Inadmissible value");
45+
}
46+
return log(val);
47+
}
48+
4149
// [[Rcpp::export]]
4250
double takeLogRcppLocation(double val) {
4351
if (val <= 0.0) {

inst/unitTests/runit.exceptions.R

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ test.rcppException <- function() {
5858
checkEquals(condition$call, quote(takeLogRcpp(-1L)))
5959
}
6060

61+
test.rcppStop <- function() {
62+
63+
# Code works normally without an exception
64+
checkIdentical(takeLog(1L), log(1L))
65+
66+
# C++ exceptions are converted to R conditions
67+
condition <- tryCatch(takeLogStop(-1L), error = identity)
68+
69+
checkIdentical(condition$message, "Inadmissible value")
70+
checkIdentical(class(condition), c("Rcpp::exception", "C++Error", "error", "condition"))
71+
72+
checkTrue(!is.null(condition$cppstack))
73+
74+
checkIdentical(class(condition$cppstack), "Rcpp_stack_trace")
75+
76+
checkEquals(condition$call, quote(takeLogStop(-1L)))
77+
}
78+
6179
test.rcppExceptionLocation <- function() {
6280

6381
# Code works normally without an exception

src/api.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,24 @@ using namespace Rcpp;
3838
#else
3939
#include <execinfo.h>
4040

41+
// Extract mangled name e.g. ./test(baz+0x14)[0x400962]
4142
static std::string demangler_one(const char* input) {
4243
static std::string buffer;
4344
buffer = input;
44-
buffer.resize(buffer.find_last_of('+') - 1);
45-
buffer.erase(
46-
buffer.begin(),
47-
buffer.begin() + buffer.find_last_of(' ') + 1
48-
);
49-
return demangle(buffer);
45+
size_t last_open = buffer.find_last_of('(');
46+
size_t last_close = buffer.find_last_of(')');
47+
if (last_open == std::string::npos ||
48+
last_close == std::string::npos) {
49+
return input;
50+
}
51+
std::string function_name = buffer.substr(last_open + 1, last_close - last_open - 1);
52+
// Strip the +0x14 (if it exists, which it does not in earlier versions of gcc)
53+
size_t function_plus = function_name.find_last_of('+');
54+
if (function_plus != std::string::npos) {
55+
function_name.resize(function_plus);
56+
}
57+
buffer.replace(last_open + 1, function_name.size(), demangle(function_name));
58+
return buffer;
5059
}
5160
#endif
5261
#endif

0 commit comments

Comments
 (0)