Skip to content

Commit ba1e576

Browse files
authored
Add protection against integer overflows in sugar functions (#1457)
* implementation of safe add/sub/mul for integers * fix duplicated define * fix couple of tests, explicitly check for overflow errors * fix functions/diff.h * fix functions/cumprod.h * fix functions/cumsum.h * move functions further down into the detail namespace * fix functions/rowSums.h * fix functions/sum.h * fix operators/minus.h * fix operators/plus.h * fix operators/times.h * update ChangeLog * couple of fixes suggested by Claude * fix plus/minus/times to work in vec<op>seq, seq<op>vec combinations
1 parent 5fd3b68 commit ba1e576

File tree

15 files changed

+503
-184
lines changed

15 files changed

+503
-184
lines changed

ChangeLog

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@
44
* inst/include/Rcpp/sugar/functions/min.h: Idem
55
* inst/tinytest/test_sugar.R: Adapt tests
66

7+
2026-02-26 Iñaki Ucar <iucar@fedoraproject.org>
8+
9+
* inst/include/Rcpp/sugar/tools/safe_math.h: New header implementing safe
10+
versions of add/sub/mul operations for integral types
11+
* inst/include/Rcpp/sugar/sugar.h: Includes the previous header
12+
13+
* inst/include/Rcpp/sugar/functions/cumprod.h: Use the previous operations
14+
* inst/include/Rcpp/sugar/functions/cumsum.h: Idem
15+
* inst/include/Rcpp/sugar/functions/diff.h: Idem, also fixed a bug where
16+
the diff was recomputed instead of returning the calculated value
17+
* inst/include/Rcpp/sugar/functions/rowSums.h: Idem
18+
* inst/include/Rcpp/sugar/functions/sum.h: Idem
19+
* inst/include/Rcpp/sugar/operators/minus.h: Idem, also fixed a bug for
20+
an incorrect Extractor specialization in Minus_Primitive_Vector
21+
* inst/include/Rcpp/sugar/operators/plus.h: Idem
22+
* inst/include/Rcpp/sugar/operators/times.h: Idem
23+
24+
* inst/tinytest/test_sugar.R: New tests covering the new operations
25+
* inst/tinytest/cpp/sugar.cpp: Idem
26+
* inst/tinytest/cpp/sugar_safe_math.cpp: Idem
27+
* inst/tinytest/cpp/sugar_safe_math_fallback.cpp: Idem
28+
729
2026-02-17 Dirk Eddelbuettel <edd@debian.org>
830

931
* DESCRIPTION (Version, Date): Roll micro version and date

inst/include/Rcpp/sugar/functions/cumprod.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//
33
// cumsum.h: Rcpp R/C++ interface class library -- cumsum
44
//
5-
// Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois
5+
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
6+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
67
//
78
// This file is part of Rcpp.
89
//
@@ -33,23 +34,23 @@ class Cumprod : public Lazy< Rcpp::Vector<RTYPE>, Cumprod<RTYPE, NA, T> > {
3334
typedef Rcpp::Vector<RTYPE> VECTOR;
3435

3536
Cumprod(const VEC_TYPE& object_) : object(object_) {}
36-
37+
3738
VECTOR get() const {
3839
R_xlen_t n = object.size();
3940
VECTOR result(n, Rcpp::traits::get_na<RTYPE>());
4041
STORAGE current = object[0];
41-
42+
4243
if (Rcpp::traits::is_na<RTYPE>(current)) return result;
4344
result[0] = current;
4445
for (R_xlen_t i = 1; i < n; i++) {
4546
current = object[i];
4647
if (Rcpp::traits::is_na<RTYPE>(current)) return result;
47-
result[i] = result[i-1] * current;
48+
result[i] = RCPP_SAFE_MUL(result[i-1], current);
4849
}
4950
return result ;
5051
}
5152
private:
52-
const VEC_TYPE& object;
53+
const VEC_TYPE& object;
5354
};
5455

5556
} // sugar
@@ -72,5 +73,5 @@ inline sugar::Cumprod<CPLXSXP, NA, T> cumprod(const VectorBase<CPLXSXP, NA, T>&
7273

7374

7475
} // Rcpp
75-
#endif // Rcpp__sugar__cumprod_h
76+
#endif // Rcpp__sugar__cumprod_h
7677

inst/include/Rcpp/sugar/functions/cumsum.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//
33
// cumsum.h: Rcpp R/C++ interface class library -- cumsum
44
//
5-
// Copyright (C) 2010 - 2011 Dirk Eddelbuettel and Romain Francois
5+
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
6+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
67
//
78
// This file is part of Rcpp.
89
//
@@ -45,7 +46,7 @@ class Cumsum : public Lazy< Rcpp::Vector<RTYPE> , Cumsum<RTYPE,NA,T> > {
4546
current = object[i] ;
4647
if( Rcpp::traits::is_na<RTYPE>(current) )
4748
return result ;
48-
result[i] = result[i-1] + current ;
49+
result[i] = RCPP_SAFE_ADD(result[i-1], current);
4950
}
5051
return result ;
5152
}

inst/include/Rcpp/sugar/functions/diff.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
//
33
// diff.h: Rcpp R/C++ interface class library -- diff
44
//
5-
// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois
5+
// Copyright (C) 2010 - 2025 Dirk Eddelbuettel and Romain Francois
6+
// Copyright (C) 2026 Dirk Eddelbuettel, Romain Francois and Iñaki Ucar
67
//
78
// This file is part of Rcpp.
89
//
@@ -51,7 +52,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, LHS_NA , Diff<RTYPE,LHS_NA,LHS_T> >
5152
set_previous(i+1, y ) ;
5253
return traits::get_na<RTYPE>() ; // NA
5354
}
54-
STORAGE res = y - previous ;
55+
STORAGE res = RCPP_SAFE_SUB(y, previous);
5556
set_previous( i+1, y) ;
5657
return res ;
5758
}
@@ -81,7 +82,7 @@ class Diff<REALSXP, LHS_NA, LHS_T> : public Rcpp::VectorBase< REALSXP, LHS_NA, D
8182
inline double operator[]( R_xlen_t i ) const {
8283
double y = lhs[i+1] ;
8384
if( previous_index != i ) previous = lhs[i] ;
84-
double res = y - previous ;
85+
double res = RCPP_SAFE_SUB(y, previous);
8586
previous = y ;
8687
previous_index = i+1 ;
8788
return res ;
@@ -105,10 +106,10 @@ class Diff<RTYPE,false,LHS_T> : public Rcpp::VectorBase< RTYPE, false , Diff<RTY
105106
inline STORAGE operator[]( R_xlen_t i ) const {
106107
STORAGE y = lhs[i+1] ;
107108
if( previous_index != i ) previous = lhs[i] ;
108-
STORAGE diff = y - previous ;
109+
STORAGE res = RCPP_SAFE_SUB(y, previous);
109110
previous = y ;
110111
previous_index = i+1 ;
111-
return y - previous ;
112+
return res;
112113
}
113114
inline R_xlen_t size() const { return lhs.size() - 1 ; }
114115

0 commit comments

Comments
 (0)