File tree Expand file tree Collapse file tree 2 files changed +11
-5
lines changed Expand file tree Collapse file tree 2 files changed +11
-5
lines changed Original file line number Diff line number Diff line change @@ -91,7 +91,11 @@ impl RFunction {
91
91
}
92
92
93
93
pub fn r_safe_eval ( expr : RObject , env : RObject ) -> crate :: Result < RObject > {
94
- unsafe {
94
+ // We could detect and cancel early exits from the r side, but we'd be at
95
+ // risk of very unlucky interrupts occurring between `rf_eval()` and our
96
+ // `on.exit()` handling. So stay on the safe side by wrapping in
97
+ // top-level-exec. This also insulates us from user handlers.
98
+ r_top_level_exec ( || unsafe {
95
99
let eval_call = RCall :: new ( r_symbol ! ( "safe_evalq" ) )
96
100
. add ( expr. sexp )
97
101
. add ( env)
@@ -120,8 +124,8 @@ pub fn r_safe_eval(expr: RObject, env: RObject) -> crate::Result<RObject> {
120
124
} ) ;
121
125
}
122
126
123
- return Ok ( RObject :: new ( out) ) ;
124
- }
127
+ Ok ( RObject :: new ( out) )
128
+ } ) ?
125
129
}
126
130
127
131
impl From < & str > for RFunction {
Original file line number Diff line number Diff line change 5
5
# - Error slot: Character vector of length 2 [message, trace], with `trace`
6
6
# possibly an empty string.
7
7
#
8
- # TODO: Prevent this function from jumping with on.exit
8
+ # We could detect and cancel early exits from here but we'd be at risk of very
9
+ # unlucky interrupts occurring between `Rf_eval()` and our `on.exit()`
10
+ # handling. So it's up to the caller to deal with early exits, for instance with
11
+ # a top-level-exec context.
9
12
safe_evalq <- function (expr , env ) {
10
13
# Create a promise to make call stack leaner
11
14
do.call(delayedAssign , list (" out" , substitute(expr ), env ))
@@ -38,7 +41,6 @@ safe_evalq <- function(expr, env) {
38
41
39
42
withCallingHandlers(
40
43
list (out , NULL ),
41
- interrupt = handler ,
42
44
error = handler
43
45
)
44
46
}
You can’t perform that action at this time.
0 commit comments