diff --git a/ChangeLog b/ChangeLog index 183695dd7..a7a9f7b57 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2026-02-27 Iñaki Ucar + + * inst/include/Rcpp/sugar/functions/max.h: Fix UB for empty integer + * inst/include/Rcpp/sugar/functions/min.h: Idem + * inst/tinytest/test_sugar.R: Adapt tests + 2026-02-17 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll micro version and date diff --git a/inst/include/Rcpp/sugar/functions/max.h b/inst/include/Rcpp/sugar/functions/max.h index de56d24f5..7f85b1457 100644 --- a/inst/include/Rcpp/sugar/functions/max.h +++ b/inst/include/Rcpp/sugar/functions/max.h @@ -1,7 +1,8 @@ // max.h: Rcpp R/C++ interface class library -- max // -// Copyright (C) 2012 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -33,7 +34,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_NegInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to max"); + return(static_cast(R_NegInf)); + } STORAGE max, current ; max = obj[0] ; @@ -60,7 +65,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_NegInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to max"); + return(static_cast(R_NegInf)); + } STORAGE max, current ; max = obj[0] ; diff --git a/inst/include/Rcpp/sugar/functions/min.h b/inst/include/Rcpp/sugar/functions/min.h index 7b77407a3..0e8b9410e 100644 --- a/inst/include/Rcpp/sugar/functions/min.h +++ b/inst/include/Rcpp/sugar/functions/min.h @@ -1,7 +1,8 @@ // Min.h: Rcpp R/C++ interface class library -- min // -// Copyright (C) 2012 - 2018 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar // // This file is part of Rcpp. // @@ -33,7 +34,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_PosInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to min"); + return(static_cast(R_PosInf)); + } STORAGE min, current ; min = obj[0] ; @@ -60,7 +65,11 @@ namespace sugar{ operator STORAGE() const { R_xlen_t n = obj.size(); - if (n == 0) return(static_cast(R_PosInf)); + if (n == 0) { + if (RTYPE != REALSXP) + Rcpp::stop("missing argument to min"); + return(static_cast(R_PosInf)); + } STORAGE min, current ; min = obj[0] ; diff --git a/inst/tinytest/test_sugar.R b/inst/tinytest/test_sugar.R index 4465cedf7..ece0c6e44 100644 --- a/inst/tinytest/test_sugar.R +++ b/inst/tinytest/test_sugar.R @@ -1623,12 +1623,10 @@ expect_error(strimws(x[1], "invalid"), info = "strimws -- bad `which` argument") ## 21 July 2018 ## min/max # test.sugar.min.max <- function() { -## min(empty) gives NA for integer, Inf for numeric (#844) -if (!isArm) expect_true(is.na(intmin(integer(0))), "min(integer(0))") +expect_error(intmin(integer(0)), "missing argument") if (!isArm) expect_equal(doublemin(numeric(0)), Inf, info = "min(numeric(0))") -## max(empty_ gives NA for integer, Inf for numeric (#844) -expect_true(is.na(intmax(integer(0))), "max(integer(0))") +expect_error(intmax(integer(0)), "missing argument") expect_equal(doublemax(numeric(0)), -Inf, info = "max(numeric(0))") ## 'normal' values