From 55b89f6adef8de41507540d443982ce33df17c93 Mon Sep 17 00:00:00 2001 From: dincerti Date: Wed, 8 Oct 2025 16:23:33 -0700 Subject: [PATCH 1/6] fix: ensure time and rate are same length --- inst/include/hesim/statmods/statmods.h | 2 +- inst/include/hesim/stats/distributions.h | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/inst/include/hesim/statmods/statmods.h b/inst/include/hesim/statmods/statmods.h index c4014b51..e9bec80c 100644 --- a/inst/include/hesim/statmods/statmods.h +++ b/inst/include/hesim/statmods/statmods.h @@ -169,7 +169,7 @@ class surv : public statmod { } else if (dist_name == "pwexp"){ int n_times = params_surv.pwexp_aux_.time_.size(); - std::vector rate(n_times + 1, 0.0); + std::vector rate(n_times, 0.0); d = new stats::piecewise_exponential(rate, params_surv.pwexp_aux_.time_); } diff --git a/inst/include/hesim/stats/distributions.h b/inst/include/hesim/stats/distributions.h index f96e8eae..0563b43b 100644 --- a/inst/include/hesim/stats/distributions.h +++ b/inst/include/hesim/stats/distributions.h @@ -317,6 +317,13 @@ class piecewise_exponential : public distribution { * Instantiates an exponential distribution with a given rate parameter. */ piecewise_exponential(std::vector rate, std::vector time){ + if (time.size() != rate.size()) { + std::ostringstream oss_time, oss_rate; + for (auto x : time) oss_time << x << " "; + for (auto x : rate) oss_rate << x << " "; + Rcpp::stop("Time and rate must be the same length.\nTime: " + oss_time.str() + "\nRate: " + oss_rate.str()); + } + rate_ = rate; time_ = time; cumrate_.resize(rate_.size()); From a2e6d17578063236edd7f04242a5f9b50a183b40 Mon Sep 17 00:00:00 2001 From: dincerti Date: Thu, 9 Oct 2025 14:36:59 -0700 Subject: [PATCH 2/6] refactor: formalize and test C++ level error when time and rate are not the same length --- inst/include/hesim/stats/distributions.h | 26 ++++++++++++++++++------ tests/testthat/test-cpp-distributions.R | 7 +++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/inst/include/hesim/stats/distributions.h b/inst/include/hesim/stats/distributions.h index 0563b43b..bfd2f04d 100644 --- a/inst/include/hesim/stats/distributions.h +++ b/inst/include/hesim/stats/distributions.h @@ -310,6 +310,25 @@ class piecewise_exponential : public distribution { std::vector cumrate_; ///< cumulative rate parameter up to each time std::vector time_; ///& time, const std::vector& rate) { + if (time.size() != rate.size()) { + std::ostringstream oss_time, oss_rate; + for (auto x : time) oss_time << x << " "; + for (auto x : rate) oss_rate << x << " "; + Rcpp::stop("'time' and 'rate' must be the same length.\n" + + std::string("time: ") + oss_time.str() + "\n" + + std::string("rate: ") + oss_rate.str()); + } + } public: /** @@ -317,12 +336,7 @@ class piecewise_exponential : public distribution { * Instantiates an exponential distribution with a given rate parameter. */ piecewise_exponential(std::vector rate, std::vector time){ - if (time.size() != rate.size()) { - std::ostringstream oss_time, oss_rate; - for (auto x : time) oss_time << x << " "; - for (auto x : rate) oss_rate << x << " "; - Rcpp::stop("Time and rate must be the same length.\nTime: " + oss_time.str() + "\nRate: " + oss_rate.str()); - } + check_same_length(time, rate); rate_ = rate; time_ = time; diff --git a/tests/testthat/test-cpp-distributions.R b/tests/testthat/test-cpp-distributions.R index 4c9a5e89..f633908e 100644 --- a/tests/testthat/test-cpp-distributions.R +++ b/tests/testthat/test-cpp-distributions.R @@ -96,6 +96,13 @@ test_that("pwexp", { expect_true(all(r >= max(time) + 1)) }) +# An error is thrown if time and rate are not the same length +expect_error( + new(PwExp, rate = c(1, 2), time = c(0, 2, 4)), + "'time' and 'rate' must be the same length." +) + + # Weibull distribution (AFT) --------------------------------------------------- test_that("weibull", { Weibull <- module$weibull From 9af1ea50c6a99c4f1bf6b6737d2b38a77ba51ce9 Mon Sep 17 00:00:00 2001 From: dincerti Date: Thu, 9 Oct 2025 14:48:20 -0700 Subject: [PATCH 3/6] docs: update news for v0.5.7 --- NEWS.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/NEWS.md b/NEWS.md index b1e87d34..d569eea8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +## hesim 0.5.7 +Fix memory access issue identified in piecewise exponential distributions by +ensuring that the `time` and `rate` vectors are of the same length. Previously, +an off-by-one allocation could cause undefined behavior on some systems. + ## hesim 0.5.6 Ensure compatibility with `ggplot v4.0.0`. From 9e057465521fdfd236729f78c02af6672b88b066 Mon Sep 17 00:00:00 2001 From: dincerti Date: Thu, 9 Oct 2025 14:54:38 -0700 Subject: [PATCH 4/6] docs: update CRAN comments --- cran-comments.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cran-comments.md b/cran-comments.md index c3e88417..6401ec47 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,9 +1,10 @@ ## Release summary -The purpose of this release is to fix errors caused by the latest release of -ggplot2. This is a resubmission that: +The purpose of this release is to fix memory access issues identified by +`clang-ASAN` and `gcc-ASAN` during the CRAN checks. -1. Updates a broken link for the data.table website. -2. Ensures all examples complete in under 10 seconds during CRAN checks. +The error was first reproduced on R-hub `clang-asan` and `gcc-asan`. After +the fix, it was then confirmed that `clang-asan` and `gcc-asan` did not +produce any errors. ## R CMD check results 0 errors | 0 warnings | 0 notes From e5c7e714b79ace52d91ec3ea08616224958d0e1a Mon Sep 17 00:00:00 2001 From: dincerti Date: Thu, 9 Oct 2025 14:57:15 -0700 Subject: [PATCH 5/6] docs: minor tweak to check_same_length documentation --- inst/include/hesim/stats/distributions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/include/hesim/stats/distributions.h b/inst/include/hesim/stats/distributions.h index bfd2f04d..1a13cb24 100644 --- a/inst/include/hesim/stats/distributions.h +++ b/inst/include/hesim/stats/distributions.h @@ -312,7 +312,7 @@ class piecewise_exponential : public distribution { /// giving the times at which the rate changes /** - * Checks that the time and rate vectors have the same length. + * Check that the time and rate vectors have the same length. * * @param time Vector of times at which the rate changes. * @param rate Vector of rate parameters. From 9cccc96667d22e760be335ba226e551645ba866a Mon Sep 17 00:00:00 2001 From: dincerti Date: Thu, 9 Oct 2025 16:02:09 -0700 Subject: [PATCH 6/6] chore: update package version --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index d0612f20..ad7cd806 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: hesim Type: Package Title: Health Economic Simulation Modeling and Decision Analysis -Version: 0.5.6 +Version: 0.5.7 Authors@R: c( person("Devin", "Incerti", , "devin.incerti@gmail.com", role = c("aut", "cre")), person("Jeroen P.", "Jansen", role = "aut"),