diff --git a/ChangeLog b/ChangeLog index a841bc970..c18ea7531 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2026-03-26 Iñaki Ucar + + * inst/include/Rcpp/internal/r_vector.h: Return null start for empty vectors + instead of an invalid pointer, which causes UB in e.g. std::copy + * inst/tinytest/test_vector.R: Add tests for std::copy + * inst/tinytest/cpp/Vector.cpp: Idem + 2026-03-26 Dirk Eddelbuettel * inst/bib/Rcpp.bib: Refreshed a few more references diff --git a/inst/include/Rcpp/internal/r_vector.h b/inst/include/Rcpp/internal/r_vector.h index 589c75fed..c6a76b6ce 100644 --- a/inst/include/Rcpp/internal/r_vector.h +++ b/inst/include/Rcpp/internal/r_vector.h @@ -3,7 +3,8 @@ // // r_vector.h: Rcpp R/C++ interface class library -- information about R vectors // -// Copyright (C) 2010 - 2017 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain François +// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar // // This file is part of Rcpp. // @@ -36,6 +37,8 @@ typename Rcpp::traits::storage_type::type* r_vector_start(SEXP x) { #define RCPP_VECTOR_START_IMPL(__RTYPE__, __ACCESSOR__) \ template <> \ inline typename Rcpp::traits::storage_type<__RTYPE__>::type* r_vector_start<__RTYPE__>(SEXP x) { \ + if (Rf_xlength(x) == 0) \ + return NULL; \ return __ACCESSOR__(x); \ } diff --git a/inst/tinytest/cpp/Vector.cpp b/inst/tinytest/cpp/Vector.cpp index 4fc26b7e8..c324aa300 100644 --- a/inst/tinytest/cpp/Vector.cpp +++ b/inst/tinytest/cpp/Vector.cpp @@ -2,7 +2,8 @@ // // Vector.cpp: Rcpp R/C++ interface class library -- Vector unit tests // -// Copyright (C) 2012 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain François +// Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar // // This file is part of Rcpp. // @@ -896,3 +897,10 @@ double NumericVector_test_out_of_bounds_read(NumericVector v, R_xlen_t i) { SEXP CharacterVector_test_out_of_bounds_read(CharacterVector v, R_xlen_t i) { return v[i]; } + +// [[Rcpp::export]] +NumericVector vec_copy(NumericVector vec1) { + NumericVector vec2(vec1.size()); + std::copy(vec1.begin(), vec1.end(), vec2.begin()); + return vec2; +} diff --git a/inst/tinytest/test_vector.R b/inst/tinytest/test_vector.R index e8138e24e..a062fba23 100644 --- a/inst/tinytest/test_vector.R +++ b/inst/tinytest/test_vector.R @@ -1,5 +1,6 @@ -## Copyright (C) 2010 - 2019 Dirk Eddelbuettel and Romain Francois +## Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain François +## Copyright (C) 2026 Dirk Eddelbuettel, Romain François and Iñaki Ucar ## ## This file is part of Rcpp. ## @@ -702,3 +703,8 @@ expect_true( !CharacterVector_test_equality_crosspolicy("foo", "bar") ) #expect_warning(CharacterVector_test_out_of_bounds_read(character(0), 0)) #expect_warning(CharacterVector_test_out_of_bounds_read(character(1), 1)) + +# https://github.com/RcppCore/Rcpp/issues/1461 +expect_equal(vec_copy(as.numeric(1:10)), as.numeric(1:10)) +expect_equal(vec_copy(numeric(0)), numeric(0)) +