[Rcpp-devel] `checkUserInterrupt()` might not be safe if Rcout is used.

Kevin Ushey kevinushey at gmail.com
Thu Jul 26 18:06:26 CEST 2018


What environment are you executing this on? (R in terminal, or with a GUI;
which OS?)

One thing to be cautious of is that many R APIs in graphical environments
will also call for processing of events, and this in turn can also imply a
check for, and handling of, interrupts. Rprintf() is in fact one such API
(and this is called behind the scenes by Rcout).

This implies something quite unfortunate: attempts to use any R APIs which
call for processing of events within a C++ context can cause a longjmp that
bypass C++ destructors and leave you in a bad state.

Fortunately, things will be better with the newer Rcpp evaluation system
from R 3.5 and above, thanks for R_UnwindProtect() and work from Lionel to
integrate that with the Rcpp evaluation model. See
https://github.com/RcppCore/Rcpp/pull/789 for some of the details on the
initial PR. We're still settling out some final details on the API but once
that's ready we'll have some documentation + hopefully an Rcpp gallery
example describing its use.

(We might also consider in Rcpp wrapping our calls to Rprintf() in
R_ToplevelExec() and 'catching' and 'rethrowing' interrupts seen, but this
might have some unintended side-effects)

Best,
Kevin

On Thu, Jul 26, 2018 at 8:18 AM Wush Wu <wush978 at gmail.com> wrote:

> Hi all,
>
> I just learned the function `checkUserInterrupt` and played with it in my
> package today. At first, everything was good. However, I sensed something
> wrong when I interrupted my function and relaunched it. In my case, the
> thread number of OpenMP decreased to 1 after an user interruption.
>
> According to the documentation, the `checkUserInterrupt` will throw an
> exception to trigger the C++ destructors on the stack. However, if I use
> `Rcout` several times (verbose mode of my function), then it will not throw
> the exception but leave the function directly.
>
> Here is a toy example to demonstrate:
> https://gist.github.com/wush978/36c4e5d8324dd14040eecb4b1dd1c631
>
> It uses `Rcout` / `std::cout` as a progressbar and check the user
> interruption. If the exception is thrown correctly, then a catch clause
> will handle the exception and write something to the `std::cerr`.
>
> If I turn off the verbose mode, then the `checkUserInterrupt` always
> throws the exception.
>
> If I turn on the verbose mode and use `jsize` to select the number of dot
> on the screen, then the `checkUserInterrupt` will exit the function
> immediately if `jsize` is large.  For example, `checkUserInterrupt` throws
> exception if `jsize = 5` but does not throw if `jsize = 100`.
>
> If I use `std::cout` instead of `Rcpp::Rcout`, then everything goes right
> again. So, there might be something wrong even if `R_TopLevelExec` is used.
>
> Well, I guess this bug might be hard to debug, but we should let the
> others aware about this at least, right?
>
> Best,
> Wush
> _______________________________________________
> Rcpp-devel mailing list
> Rcpp-devel at lists.r-forge.r-project.org
> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20180726/cf9fb294/attachment-0001.html>


More information about the Rcpp-devel mailing list