From a0c4bba6ff562295788eba277d9780a45a2c9e61 Mon Sep 17 00:00:00 2001 From: perrydv Date: Sun, 9 Aug 2026 18:52:00 -0700 Subject: [PATCH 1/2] Avoid std::copy calls that make 0 length copy, possibly reading from an invalid pointer (UBSAN issue) --- packages/nimble/DESCRIPTION | 4 +- packages/nimble/inst/include/nimble/NimArr.h | 42 ++++++++++++------- .../inst/include/nimble/RcppNimbleUtils.h | 18 +++++--- .../inst/include/nimble/accessorClasses.h | 7 ++-- .../include/nimble/nimbleCppADbaseClass.cpp | 10 +++-- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/packages/nimble/DESCRIPTION b/packages/nimble/DESCRIPTION index 5ca30c937..080062b7c 100644 --- a/packages/nimble/DESCRIPTION +++ b/packages/nimble/DESCRIPTION @@ -15,8 +15,8 @@ Description: A system for writing hierarchical statistical models largely of MCMC as the main goal of the 'BUGS'/'JAGS' language for writing models, one can use 'NIMBLE' for writing arbitrary other kinds of model-generic algorithms as well. A full User Manual is available at . -Version: 1.4.2 -Date: 2026-04-01 +Version: 1.4.3 +Date: 2026-08-09 Maintainer: Christopher Paciorek Authors@R: c( person("Perry", "de Valpine", role = "aut"), diff --git a/packages/nimble/inst/include/nimble/NimArr.h b/packages/nimble/inst/include/nimble/NimArr.h index 8d134dc8a..a1a126f42 100644 --- a/packages/nimble/inst/include/nimble/NimArr.h +++ b/packages/nimble/inst/include/nimble/NimArr.h @@ -72,7 +72,8 @@ template target.getVptrRef() = ans; target.mapCopy(val); } else { - std::copy(val.getConstPtr(), val.getConstPtr() + length, *ans); + if(length > 0) + std::copy(val.getConstPtr(), val.getConstPtr() + length, *ans); } } @@ -172,7 +173,8 @@ class NimArr<1, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(size1); NimArrBase::own_v = true; - std::copy(other.v, other.v + size1, NimArrBase::v); + if (size1 > 0) + std::copy(other.v, other.v + size1, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -211,7 +213,8 @@ class NimArr<1, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return (*this); @@ -238,7 +241,8 @@ class NimArr<1, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(size1); NimArrBase::own_v = true; - std::copy(other.v, other.v + size1, NimArrBase::v); + if (size1 > 0) + std::copy(other.v, other.v + size1, NimArrBase::v); } NimArrBase::setVptr(); } @@ -421,7 +425,8 @@ class NimArr<2, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -454,7 +459,8 @@ class NimArr<2, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); } @@ -666,7 +672,8 @@ class NimArr<3, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -704,7 +711,8 @@ class NimArr<3, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); } @@ -949,7 +957,8 @@ class NimArr<4, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -994,7 +1003,8 @@ class NimArr<4, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); } @@ -1270,7 +1280,8 @@ class NimArr<5, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -1321,7 +1332,8 @@ class NimArr<5, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); } @@ -1626,7 +1638,8 @@ class NimArr<6, T> : public NimArrBase { if (NimArrBase::own_v) nimble_free(NimArrBase::v); NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); return *this; @@ -1683,7 +1696,8 @@ class NimArr<6, T> : public NimArrBase { } else { NimArrBase::v = nimble_malloc(NimArrBase::NAlength); NimArrBase::own_v = true; - std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); + if (NimArrBase::NAlength > 0) + std::copy(other.v, other.v + NimArrBase::NAlength, NimArrBase::v); } NimArrBase::setVptr(); } diff --git a/packages/nimble/inst/include/nimble/RcppNimbleUtils.h b/packages/nimble/inst/include/nimble/RcppNimbleUtils.h index 14d149e3b..5cea58c92 100644 --- a/packages/nimble/inst/include/nimble/RcppNimbleUtils.h +++ b/packages/nimble/inst/include/nimble/RcppNimbleUtils.h @@ -245,13 +245,15 @@ void SEXP_2_NimArr(SEXP Sn, NimArr &ans) { ans.setSize(inputDims); int nn = LENGTH(Sn); if(Rf_isReal(Sn)) { - std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); + if(nn > 0) + std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); } else { NIM_ASSERT3(Rf_isInteger(Sn) || Rf_isLogical(Sn), "could not handle input of type %s to SEXP_2_NimArr<%d, double>\n", Rf_type2char(TYPEOF(Sn)), ndim); int *iSn = Rf_isInteger(Sn) ? INTEGER(Sn) : LOGICAL(Sn); - std::copy(iSn, iSn + nn, ans.getPtr()); //v); + if(nn > 0) + std::copy(iSn, iSn + nn, ans.getPtr()); //v); } } @@ -269,13 +271,15 @@ void SEXP_2_NimArr(SEXP Sn, NimArr &ans) { ans.setSize(inputDims); int nn = LENGTH(Sn); if(Rf_isReal(Sn)) { - std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); + if(nn > 0) + std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); } else { NIM_ASSERT3(Rf_isInteger(Sn) || Rf_isLogical(Sn), "could not handle input type %s to SEXP_2_NimArr<%d, int>\n", Rf_type2char(TYPEOF(Sn)), ndim); int *iSn = Rf_isInteger(Sn) ? INTEGER(Sn) : LOGICAL(Sn); - std::copy(iSn, iSn + nn, ans.getPtr()); //v); + if(nn > 0) + std::copy(iSn, iSn + nn, ans.getPtr()); //v); } } @@ -292,13 +296,15 @@ void SEXP_2_NimArr(SEXP Sn, NimArr &ans) { ans.setSize(inputDims); int nn = LENGTH(Sn); if(Rf_isReal(Sn)) { - std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); + if(nn > 0) + std::copy(REAL(Sn), REAL(Sn) + nn, ans.getPtr() ); } else { NIM_ASSERT3(Rf_isInteger(Sn) || Rf_isLogical(Sn), "could not handle input type %s to SEXP_2_NimArr<%d, bool>\n", Rf_type2char(TYPEOF(Sn)), ndim); int *iSn = Rf_isInteger(Sn) ? INTEGER(Sn) : LOGICAL(Sn); - std::copy(iSn, iSn + nn, ans.getPtr()); //v); + if(nn > 0) + std::copy(iSn, iSn + nn, ans.getPtr()); //v); } } diff --git a/packages/nimble/inst/include/nimble/accessorClasses.h b/packages/nimble/inst/include/nimble/accessorClasses.h index 99ab9ed65..3868aab8c 100644 --- a/packages/nimble/inst/include/nimble/accessorClasses.h +++ b/packages/nimble/inst/include/nimble/accessorClasses.h @@ -739,9 +739,10 @@ class NodeVectorClassNew_derivs : public NodeVectorClassNew { NimArrVars.setSize(length_wrt); getValues(NimArrVars, model_wrt_accessor); - std::copy(NimArrVars.getPtr(), - NimArrVars.getPtr() + length_wrt, - independentVars.begin()); + if(length_wrt > 0) + std::copy(NimArrVars.getPtr(), + NimArrVars.getPtr() + length_wrt, + independentVars.begin()); //std::cout<<"done runTape_setInd"< &independentVars, if (ordersFound[0]) { ansList->value.setSize(res_dimy_o0, false, false); if(outAlly_o0) { - std::copy(value_ans.begin(), value_ans.end(), ansList->value.getPtr()); + if(!value_ans.empty()) + std::copy(value_ans.begin(), value_ans.end(), ansList->value.getPtr()); } else { BASE *LHS = ansList->value.getPtr(); for(size_t iii=0;iii 0) + std::copy(NimArrVars.getPtr(), + NimArrVars.getPtr() + length_wrt, + ADinfo.independentVars.begin()); /* set dynamic */ // Copy extraInput (CppAD "dynamic") values from the model into the dynamicVars // *and* set them in the tape. From e78fc6a8f270519a5c19b79fc7856dc3ec7e2070 Mon Sep 17 00:00:00 2001 From: perrydv Date: Mon, 10 Aug 2026 14:41:51 -0700 Subject: [PATCH 2/2] reset Version and Date in DESCRIPTION to previous values --- packages/nimble/DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nimble/DESCRIPTION b/packages/nimble/DESCRIPTION index 080062b7c..5ca30c937 100644 --- a/packages/nimble/DESCRIPTION +++ b/packages/nimble/DESCRIPTION @@ -15,8 +15,8 @@ Description: A system for writing hierarchical statistical models largely of MCMC as the main goal of the 'BUGS'/'JAGS' language for writing models, one can use 'NIMBLE' for writing arbitrary other kinds of model-generic algorithms as well. A full User Manual is available at . -Version: 1.4.3 -Date: 2026-08-09 +Version: 1.4.2 +Date: 2026-04-01 Maintainer: Christopher Paciorek Authors@R: c( person("Perry", "de Valpine", role = "aut"),