Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
2026-08-03 Kevin Ushey <kevinushey@gmail.com>

* src/module.cpp (class__newInstance, CppMethod__invoke,
CppMethod__invoke_void, CppMethod__invoke_notvoid): Convert C++
exceptions to R errors at these .External entry points, so that
e.g. calling a method on an uninitialized module object raises
the intended R error rather than terminating the R session
(#1495)
* inst/tinytest/test_module.R: Add regression test

2026-07-24 Dirk Eddelbuettel <edd@debian.org>

* DESCRIPTION (Version, Date): Roll micro version and date
Expand Down
6 changes: 6 additions & 0 deletions inst/tinytest/test_module.R
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ x10 <- runif(10, 10.0, 20.0)
set.seed(123)
expect_equal(r$get(10), x10)

## calling a method on an uninitialized module object (created via the
## dummy-object path for classes without a default constructor) should
## raise an R error rather than terminating the R session (#1495)
r <- new( ModuleRandomizer )
expect_error( r$get(10L), "not initialized" )

# test.Module.flexible.semantics <- function( ){
expect_equal( test_reference( seq(0,10) ), 11L )
expect_equal( test_const_reference( seq(0,10) ), 11L )
Expand Down
10 changes: 9 additions & 1 deletion src/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ END_RCPP
} // #nocov end

SEXP class__newInstance(SEXP args) {
BEGIN_RCPP
SEXP p = CDR(args);

XP_Module module(CAR(p)); p = CDR(p);
XP_Class clazz(CAR(p)); p = CDR(p);
UNPACK_EXTERNAL_ARGS(cargs,p)
return clazz->newInstance(cargs, nargs);
END_RCPP
}

// relies on being set in .onLoad()
Expand All @@ -164,6 +166,7 @@ SEXP class__dummyInstance(SEXP args) {
}

SEXP CppMethod__invoke(SEXP args) { // #nocov start
BEGIN_RCPP
SEXP p = CDR(args);

// the external pointer to the class
Expand All @@ -180,9 +183,11 @@ SEXP CppMethod__invoke(SEXP args) { // #nocov start
UNPACK_EXTERNAL_ARGS(cargs,p)

return clazz->invoke(met, obj, cargs, nargs);
} // #nocov end
END_RCPP
} // #nocov end

SEXP CppMethod__invoke_void(SEXP args) {
BEGIN_RCPP
SEXP p = CDR(args);

// the external pointer to the class
Expand All @@ -199,9 +204,11 @@ SEXP CppMethod__invoke_void(SEXP args) {
UNPACK_EXTERNAL_ARGS(cargs,p)
clazz->invoke_void(met, obj, cargs, nargs);
return R_NilValue;
END_RCPP
}

SEXP CppMethod__invoke_notvoid(SEXP args) {
BEGIN_RCPP
SEXP p = CDR(args);

// the external pointer to the class
Expand All @@ -218,6 +225,7 @@ SEXP CppMethod__invoke_notvoid(SEXP args) {
UNPACK_EXTERNAL_ARGS(cargs,p)

return clazz->invoke_notvoid(met, obj, cargs, nargs);
END_RCPP
}

namespace Rcpp{
Expand Down
Loading