Skip to content

turn exceptions during module initialization into r errors - #1526

Open
kevinushey wants to merge 1 commit into
masterfrom
bugfix/module-boot-exceptions
Open

kevinushey wants to merge 1 commit into
masterfrom
bugfix/module-boot-exceptions

Conversation

@kevinushey

Copy link
Copy Markdown
Contributor

Fixes #1525.

The boot function generated by RCPP_MODULE is an extern "C" entry point called from R via .Call(), but had no BEGIN_RCPP/END_RCPP. Any C++ exception thrown by the module body, such as Rcpp's own std::range_error("no such class") from .derives<T>() with a misspelled parent, escaped into R and std::terminate() aborted the session. It also skipped ::setCurrentScope( 0 ), leaving the global module scope pointing at the half-initialized module. See #1525 for the reprex. This is the boot-function counterpart of #1495 / #1496.

Changes (inst/include/Rcpp/Module.h):

  • RCPP_MODULE: the boot function body is wrapped in BEGIN_RCPP/END_RCPP, so exceptions become R errors like in every other .Call entry point.
  • New Rcpp::internal::ModuleScope, a small RAII guard that sets the current module scope and clears it in its destructor, so the scope is reset on the error path as well as on success.

The change is confined to the macro, so it applies to a package once it is rebuilt; nothing in Rcpp.so changes. One caller-visible difference: code that calls the boot function directly from C++ instead of through .Call(), such as RInside's LOAD_RCPP_MODULE, now gets an R error rather than a C++ exception when the module body throws. Previously a throwing module body was fatal whenever it was loaded from R, so this only matters for that direct-call path.

Tests:

  • inst/tinytest/cpp/ModuleInitError.cpp: a module whose body throws (derives() with a parent that was never exposed).
  • inst/tinytest/test_module.R: sourceCpp() of that file raises the no such class R error, and afterwards the current module scope is cleared (checked through a small exported helper added to cpp/Module.cpp).

Verification:

  • The reprex from an exception while a module initializes aborts the R session #1525 aborts (SIGABRT, exit code 134) against current master and prints result: no such class with exit code 0 against this branch.
  • Against master the new test aborts the test process the same way; on this branch test_module.R (47/47), test_modref.R, test_expose_class.R and test_module_client_package.R pass with RunAllRcppTests=yes RunVerboseRcppTests=yes (R 4.6.1, macOS).
  • Compiling the test modules with -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wunreachable-code reports no warnings from the new macro or guard.

Checklist

  • Code compiles correctly
  • R CMD check still passes all tests (module test files run locally as above)
  • Preferably, new tests were added which fail without the change (without the fix, the new test terminates the test process)
  • Document the changes by file in ChangeLog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

an exception while a module initializes aborts the R session

1 participant