@@ -214,4 +214,55 @@ if (.runThisTest) {
214214 checkTrue(nchar(Rcpp ::: bib()) > 0 , msg = " bib file" )
215215 }
216216
217+ test.stackUnwinds <- function () {
218+ # On old versions of R, Rcpp_fast_eval() falls back to Rcpp_eval() and
219+ # leaks on longjumps
220+ hasUnwind <- getRversion() > = " 3.5.0"
221+ checkUnwound <- if (hasUnwind ) checkTrue else function (x ) checkTrue(! x )
222+ testEvalUnwind <- function (expr , indicator ) {
223+ testEvalUnwindImpl(expr , parent.frame(), indicator )
224+ }
225+
226+ # On errors - Always unwound
227+ unwound <- FALSE
228+ out <- tryCatch(testEvalUnwind(quote(stop(" err" )), unwound ), error = identity )
229+ checkTrue(unwound )
230+ msg <- if (hasUnwind ) " err" else " Evaluation error: err."
231+ checkIdentical(out $ message , msg )
232+
233+ # On interrupts - Always unwound
234+ unwound <- FALSE
235+ expr <- quote({
236+ repeat testSendInterrupt()
237+ " returned"
238+ })
239+ out <- tryCatch(testEvalUnwind(expr , unwound ), interrupt = function (c ) " onintr" )
240+ checkTrue(unwound )
241+ checkIdentical(out , " onintr" )
242+
243+ # On caught conditions
244+ unwound <- FALSE
245+ expr <- quote(signalCondition(simpleCondition(" cnd" )))
246+ cnd <- tryCatch(testEvalUnwind(expr , unwound ), condition = identity )
247+ checkTrue(inherits(cnd , " simpleCondition" ))
248+ checkUnwound(unwound )
249+
250+ # On restart jumps
251+ unwound <- FALSE
252+ expr <- quote(invokeRestart(" rst" ))
253+ out <- withRestarts(testEvalUnwind(expr , unwound ), rst = function (... ) " restarted" )
254+ checkIdentical(out , " restarted" )
255+ checkUnwound(unwound )
256+
257+ # On returns
258+ unwound <- FALSE
259+ expr <- quote(signalCondition(simpleCondition(NULL )))
260+ out <- callCC(function (k )
261+ withCallingHandlers(testEvalUnwind(expr , unwound ),
262+ simpleCondition = function (e ) k(" jumped" )
263+ )
264+ )
265+ checkIdentical(out , " jumped" )
266+ checkUnwound(unwound )
267+ }
217268}
0 commit comments