Skip to content

Commit 10a02e2

Browse files
committed
use 'Rf_mkCharLenCE() as appropriate
1 parent a669a19 commit 10a02e2

File tree

6 files changed

+32
-4
lines changed

6 files changed

+32
-4
lines changed

ChangeLog

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2018-10-25 Kevin Ushey <[email protected]>
2+
3+
* inst/include/Rcpp/String.h: Use Rf_mkCharLenCE() as appropriate
4+
* inst/unitTests/cpp/String.cpp: Add unit tests
5+
* inst/unitTests/runit.String.R: Add unit tests
6+
17
2018-10-12 Dirk Eddelbuettel <[email protected]>
28

39
* DESCRIPTION (Date, Version): Roll minor version

inst/NEWS.Rd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
\item The constructor for \code{NumericMatrix(not_init(n,k))} was
1313
corrected (Romain in \ghpr{904}, Dirk in \ghpr{905}, and also
1414
Romain in \ghpr{908} fixing \ghpr{907}).
15+
\item Rcpp::String no longer silently drops embedded NUL bytes
16+
in strings. Instead, the new Rcpp exception `embedded_nul_in_string`
17+
is thrown. (\ghit{916})
1518
}
1619
\item Changes in Rcpp Deployment:
1720
\itemize{

inst/include/Rcpp/String.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,9 +364,15 @@ namespace Rcpp {
364364
}
365365

366366

367+
inline SEXP get_sexp_impl() const {
368+
if (buffer.find('\0') != std::string::npos)
369+
throw embedded_nul_in_string();
370+
return Rf_mkCharLenCE(buffer.c_str(), buffer.size(), enc);
371+
}
372+
367373
inline SEXP get_sexp() const {
368374
RCPP_STRING_DEBUG_1("String::get_sexp const (valid = %d) ", valid);
369-
return valid ? data : Rf_mkCharCE(buffer.c_str(), enc);
375+
return valid ? data : get_sexp_impl();
370376
}
371377

372378
inline SEXP get_sexp() {
@@ -395,9 +401,11 @@ namespace Rcpp {
395401
enc = encoding;
396402

397403
if (valid) {
398-
data = Rcpp_ReplaceObject(data, Rf_mkCharCE(Rf_translateCharUTF8(data), encoding));
404+
// TODO: may longjmp on failure to translate?
405+
const char* translated = Rf_translateCharUTF8(data);
406+
data = Rcpp_ReplaceObject(data, Rf_mkCharCE(translated, encoding));
399407
} else {
400-
data = Rf_mkCharCE(buffer.c_str(), encoding);
408+
data = get_sexp_impl();
401409
Rcpp_PreserveObject(data);
402410
valid = true;
403411
}
@@ -469,7 +477,7 @@ namespace Rcpp {
469477
inline void setData() {
470478
RCPP_STRING_DEBUG("setData");
471479
if (!valid) {
472-
data = Rf_mkCharCE(buffer.c_str(), enc);
480+
data = get_sexp_impl();
473481
Rcpp_PreserveObject(data);
474482
valid = true;
475483
}

inst/include/Rcpp/exceptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ namespace Rcpp {
208208
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
209209
RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "No such function.")
210210
RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "Promise not yet evaluated.")
211+
RCPP_SIMPLE_EXCEPTION_CLASS(embedded_nul_in_string, "Embedded NUL in string.")
211212

212213
// Promoted
213214
RCPP_EXCEPTION_CLASS(no_such_slot, "No such slot")

inst/unitTests/cpp/String.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,9 @@ String test_String_ctor_encoding2() {
114114
y.set_encoding(CE_UTF8);
115115
return y;
116116
}
117+
118+
// [[Rcpp::export]]
119+
String test_String_embeddedNul() {
120+
std::string bad("abc\0abc", 7);
121+
return String(bad);
122+
}

inst/unitTests/runit.String.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,8 @@ if (.runThisTest) {
9494
checkEquals(Encoding(test_String_ctor_encoding2()), "UTF-8")
9595
}
9696

97+
test.String.embeddedNul <- function() {
98+
checkException(test_String_embeddedNul())
99+
}
100+
97101
}

0 commit comments

Comments
 (0)