From 1cbc4adb2dd729a231553e4cab5397da73a6beb3 Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Mon, 9 Sep 2024 08:12:01 -0400 Subject: [PATCH 1/2] fix segfault from readline; avoid unnecessary string copy --- src/RcppExports.cpp | 4 ++-- src/readline.cpp | 27 +++++++++++++-------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 7c1affef1..59c26f94d 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -824,12 +824,12 @@ BEGIN_RCPP END_RCPP } // readline -SEXP readline(const std::string& prompt); +SEXP readline(const char* prompt); RcppExport SEXP _reticulate_readline(SEXP promptSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< const std::string& >::type prompt(promptSEXP); + Rcpp::traits::input_parameter< const char* >::type prompt(promptSEXP); rcpp_result_gen = Rcpp::wrap(readline(prompt)); return rcpp_result_gen; END_RCPP diff --git a/src/readline.cpp b/src/readline.cpp index a151638f8..e3bf3aaf5 100644 --- a/src/readline.cpp +++ b/src/readline.cpp @@ -1,31 +1,30 @@ - #include #include -#include +#include // for strlen, strchr #define READLINE_BUFFER_SIZE (8192) extern "C" int R_ReadConsole(const char*, unsigned char*, int, int); // [[Rcpp::export]] -SEXP readline(const std::string& prompt) +SEXP readline(const char* prompt) { // read user input (ensure null termination) char buffer[READLINE_BUFFER_SIZE]; - R_ReadConsole(prompt.c_str(), (unsigned char*) buffer, READLINE_BUFFER_SIZE, 1); - buffer[READLINE_BUFFER_SIZE - 1] = '\0'; + if (R_ReadConsole(prompt, (unsigned char*) buffer, READLINE_BUFFER_SIZE, 1) == 0) + return R_NilValue; - // construct resulting string - std::string result(buffer, buffer + strlen(buffer)); + buffer[READLINE_BUFFER_SIZE - 1] = '\0'; // Ensure null termination - // truncate to location of inserted newline. if not found, assume - // the user canceled input with e.g. R_EOF - std::string::size_type index = result.find('\n'); - if (index == std::string::npos) - return R_NilValue; + // Find the location of the newline character, if any + char* newline_pos = strchr(buffer, '\n'); + if (newline_pos == nullptr) + return R_NilValue; // If no newline found, assume user canceled + + // Determine length up to the newline (excluding the trailing newline) + size_t input_length = newline_pos - buffer; - // return result (leaving out trailing newline) SEXP resultSEXP = PROTECT(Rf_allocVector(STRSXP, 1)); - SET_STRING_ELT(resultSEXP, 0, Rf_mkCharLen(buffer, index)); + SET_STRING_ELT(resultSEXP, 0, Rf_mkCharLen(buffer, input_length)); UNPROTECT(1); return resultSEXP; } From 0c122aad11917d52579118c87df531d367174daf Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Mon, 9 Sep 2024 08:32:36 -0400 Subject: [PATCH 2/2] add NEWS --- NEWS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NEWS.md b/NEWS.md index e3a53eaf2..fdb0ef4a7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,9 @@ - Fixed segfault encountered when running Python finalizer (#1663, #1664) +- Fixed segfault encountered in RStudio when rapidly switching + between R and Python chunks in a Quarto document (#1665). + # reticulate 1.39.0 - Python background threads can now run in parallel with the R session (#1641).