23
23
24
24
#if (defined(RCPP_PROTECTED_EVAL) && defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0))
25
25
#define RCPP_USE_PROTECT_UNWIND
26
+ #include < csetjmp>
26
27
#endif
27
28
28
29
@@ -31,23 +32,25 @@ namespace internal {
31
32
32
33
#ifdef RCPP_USE_PROTECT_UNWIND
33
34
35
+ // Store the jump buffer as a static variable in function scope
36
+ // because inline variables are a C++17 extension.
37
+ inline std::jmp_buf* get_jmpbuf_ptr () {
38
+ static std::jmp_buf jmpbuf;
39
+ return &jmpbuf;
40
+ }
41
+
34
42
struct EvalData {
35
43
SEXP expr;
36
44
SEXP env;
37
45
EvalData (SEXP expr_, SEXP env_) : expr(expr_), env(env_) { }
38
46
};
39
47
48
+ // First jump back to the protected context with a C longjmp because
49
+ // `Rcpp_protected_eval()` is called from C and we can't safely throw
50
+ // exceptions across C frames.
40
51
inline void Rcpp_maybe_throw (void * data, Rboolean jump) {
41
52
if (jump) {
42
- SEXP token = static_cast <SEXP>(data);
43
-
44
- // Keep the token protected while unwinding because R code might run
45
- // in C++ destructors. Can't use PROTECT() for this because
46
- // UNPROTECT() might be called in a destructor, for instance if a
47
- // Shield<SEXP> is on the stack.
48
- ::R_PreserveObject (token);
49
-
50
- throw LongjumpException (token);
53
+ longjmp (*internal::get_jmpbuf_ptr (), 1 );
51
54
}
52
55
}
53
56
@@ -78,6 +81,17 @@ namespace internal {
78
81
inline SEXP Rcpp_fast_eval (SEXP expr, SEXP env) {
79
82
internal::EvalData data (expr, env);
80
83
Shield<SEXP> token (::R_MakeUnwindCont ());
84
+
85
+ if (setjmp (*internal::get_jmpbuf_ptr ())) {
86
+ // Keep the token protected while unwinding because R code might run
87
+ // in C++ destructors. Can't use PROTECT() for this because
88
+ // UNPROTECT() might be called in a destructor, for instance if a
89
+ // Shield<SEXP> is on the stack.
90
+ ::R_PreserveObject (token);
91
+
92
+ throw internal::LongjumpException (token);
93
+ }
94
+
81
95
return ::R_UnwindProtect (internal::Rcpp_protected_eval, &data,
82
96
internal::Rcpp_maybe_throw, token,
83
97
token);
0 commit comments