1 /*
2 * RExec.hpp
3 *
4 * Copyright (C) 2021 by RStudio, PBC
5 *
6 * Unless you have received this program directly from RStudio pursuant
7 * to the terms of a commercial license agreement with RStudio, then
8 * this program is licensed to you under the terms of version 3 of the
9 * GNU Affero General Public License. This program is distributed WITHOUT
10 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
12 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
13 *
14 */
15
16 #ifndef R_R_EXEC_HPP
17 #define R_R_EXEC_HPP
18
19 #include <string>
20 #include <vector>
21 #include <stdexcept>
22
23 #include <boost/utility.hpp>
24 #include <boost/scoped_ptr.hpp>
25 #include <boost/function.hpp>
26
27 #include <shared_core/Error.hpp>
28 #include <core/system/System.hpp>
29
30 #include <r/RSexp.hpp>
31 #include <r/RInterface.hpp>
32
33
34 namespace rstudio {
35 namespace core {
36 class FilePath;
37 }
38 }
39
40 // IMPORTANT NOTE: all code in r::exec must provide "no jump" guarantee.
41 // See comment in RInternal.hpp for more info on this
42
43 namespace rstudio {
44 namespace r {
45 namespace exec {
46
47 // safe (no r error longjump) execution of abritrary nullary function
48 core::Error executeSafely(boost::function<void()> function);
49
50 typedef boost::function<bool()> MainThreadFunction;
51
52 // helper class for variation of executeSafely w/ return value (impl below)
53 template <typename T>
54 class ExecuteTargetWithReturn
55 {
56 public:
ExecuteTargetWithReturn(const boost::function<T ()> & function,T * pReturn)57 ExecuteTargetWithReturn(const boost::function<T()>& function, T* pReturn)
58 : function_(function), pReturn_(pReturn) {}
59
60 // COPYING: via compiler (copyable members)
61
operator ()()62 void operator()() { *pReturn_ = function_(); }
63
64 private:
65 boost::function<T()> function_;
66 T* pReturn_;
67 };
68
69 // safe (no r error longjump) execution of abritrary nullary function w/ return
70 template <typename T>
executeSafely(boost::function<T ()> function,T * pReturn)71 core::Error executeSafely(boost::function<T()> function, T* pReturn)
72 {
73 ExecuteTargetWithReturn<T> target(function, pReturn);
74 return executeSafely(target);
75 }
76
77 // flags that can be set during evaluation
78 enum EvalFlags
79 {
80 EvalFlagsNone = 0,
81 EvalFlagsSuppressWarnings = 1,
82 EvalFlagsSuppressMessages = 2
83 };
84
operator |(EvalFlags lhs,EvalFlags rhs)85 inline EvalFlags operator|(EvalFlags lhs, EvalFlags rhs)
86 {
87 return static_cast<EvalFlags>(static_cast<int>(lhs) | static_cast<int>(rhs));
88 }
89
90 // parse and evaluate expressions
91 core::Error executeCallUnsafe(SEXP callSEXP,
92 SEXP envirSEXP,
93 SEXP* pResultSEXP,
94 sexp::Protect* pProtect);
95
96 core::Error executeStringUnsafe(const std::string& str,
97 SEXP* pSEXP,
98 sexp::Protect* pProtect);
99
100 core::Error executeStringUnsafe(const std::string& str,
101 SEXP envirSEXP,
102 SEXP* pSEXP,
103 sexp::Protect* pProtect);
104
105 core::Error executeString(const std::string& str);
106
107 core::Error evaluateString(const std::string& str,
108 SEXP* pSEXP,
109 sexp::Protect* pProtect,
110 EvalFlags flags = EvalFlagsNone);
111
112 template <typename T>
evaluateString(const std::string & str,T * pValue)113 core::Error evaluateString(const std::string& str, T* pValue)
114 {
115 sexp::Protect rProtect;
116 SEXP valueSEXP;
117 core::Error error = evaluateString(str, &valueSEXP, &rProtect);
118 if (error)
119 return error;
120
121 return sexp::extract(valueSEXP, pValue);
122 }
123
124 // call R functions
125 class RFunction : boost::noncopyable
126 {
127 public:
128
129 template <typename... T>
RFunction(const std::string & name,const T &...params)130 explicit RFunction(const std::string& name, const T&... params)
131 : functionSEXP_(R_UnboundValue)
132 {
133 commonInit(name);
134 initParams(params...);
135 }
136
137 explicit RFunction(SEXP functionSEXP);
138
139 ~RFunction();
140
141 // COPYING: boost::noncopyable
142
addParam(SEXP param)143 RFunction& addParam(SEXP param)
144 {
145 addParam(std::string(), param);
146 return *this;
147 }
148
149 template <typename T>
addParam(const T & param)150 RFunction& addParam(const T& param)
151 {
152 addParam(std::string(), param);
153 return *this;
154 }
155
addParam(const std::string & name,SEXP param)156 RFunction& addParam(const std::string& name, SEXP param)
157 {
158 params_.push_back(Param(name, param));
159 return *this;
160 }
161
162 template <typename T>
addParam(const std::string & name,const T & param)163 RFunction& addParam(const std::string& name, const T& param)
164 {
165 r::sexp::Protect protect;
166 SEXP paramSEXP = sexp::create(param, &protect);
167 preserver_.add(paramSEXP);
168 params_.push_back(Param(name, paramSEXP));
169 return *this;
170 }
171
172 template <typename T>
addUtf8Param(const T & param)173 RFunction& addUtf8Param(const T& param)
174 {
175 return addUtf8Param(std::string(), param);
176 }
177
178 template <typename T>
addUtf8Param(const std::string & name,const T & param)179 RFunction& addUtf8Param(const std::string& name, const T& param)
180 {
181 r::sexp::Protect protect;
182 SEXP paramSEXP = sexp::createUtf8(param, &protect);
183 preserver_.add(paramSEXP);
184 params_.push_back(Param(name, paramSEXP));
185 return *this;
186 }
187
188 core::Error call(SEXP evalNS = R_GlobalEnv, bool safely = true);
189 core::Error callUnsafe();
190
191 core::Error call(SEXP* pResultSEXP, sexp::Protect* pProtect);
192 core::Error call(SEXP evalNS, SEXP* pResultSEXP, sexp::Protect* pProtect);
193 core::Error call(SEXP evalNS, bool safely, SEXP* pResultSEXP,
194 sexp::Protect* pProtect);
195
196 template <typename T>
call(T * pValue)197 core::Error call(T* pValue)
198 {
199 return call(R_GlobalEnv, pValue);
200 }
201
202 template <typename T>
call(SEXP evalNS,T * pValue)203 core::Error call(SEXP evalNS, T* pValue)
204 {
205 // call the function
206 sexp::Protect rProtect;
207 SEXP resultSEXP;
208 core::Error error = call(evalNS, &resultSEXP, &rProtect);
209 if (error)
210 return error;
211
212 // convert result to c++ accessible type
213 return sexp::extract(resultSEXP, pValue);
214 }
215
216 template <typename T>
callUtf8(T * pValue)217 core::Error callUtf8(T* pValue)
218 {
219 // call the function
220 sexp::Protect rProtect;
221 SEXP resultSEXP;
222 core::Error error = call(R_GlobalEnv, &resultSEXP, &rProtect);
223 if (error)
224 return error;
225
226 // convert result to c++ accessible type
227 return sexp::extract(resultSEXP, pValue, true);
228 }
229
230 private:
231 void commonInit(const std::string& functionName);
232
initParams()233 void initParams()
234 {
235 }
236
237 template <typename T, typename... Rest>
initParams(const T & param,const Rest &...rest)238 void initParams(const T& param, const Rest&... rest)
239 {
240 addParam(std::string(), param);
241 initParams(rest...);
242 }
243
244 private:
245 // preserve SEXPs
246 r::sexp::SEXPPreserver preserver_;
247
248 // function
249 SEXP functionSEXP_;
250
251 // function name (optional)
252 std::string functionName_;
253
254 // params
255 struct Param
256 {
Paramrstudio::r::exec::RFunction::Param257 Param(const std::string& name, SEXP valueSEXP)
258 : name(name), valueSEXP(valueSEXP)
259 {
260 }
261 std::string name;
262 SEXP valueSEXP;
263 };
264 std::vector<Param> params_;
265 };
266
267 void warning(const std::string& warning);
268
269 void message(const std::string& message);
270
271 // special exception type used to raise R errors. allows for correct
272 // exiting from c++ context (with destructors called, etc.) while still
273 // propagating the error to a point where it will be re-raised to r
274 // using Rf_error
275 #define R_ERROR_BUFF_SIZE 256
276 class RErrorException : public std::exception
277 {
278 public:
RErrorException(const std::string & message)279 RErrorException(const std::string& message)
280 {
281 size_t length = message.copy(msgBuff_, R_ERROR_BUFF_SIZE);
282 msgBuff_[length] = '\0';
283 }
284
message() const285 const char* message() const { return msgBuff_; }
286
287 private:
288 char msgBuff_[R_ERROR_BUFF_SIZE+1];
289 };
290
291
292 core::FilePath rBinaryPath();
293
294 core::Error system(const std::string& command, std::string* pOutput);
295
296 // raise error and get last error message
297 void error(const std::string& message);
298 void errorCall(SEXP call, const std::string& message);
299 std::string getErrorMessage();
300
301 bool interruptsPending();
302 void setInterruptsPending(bool pending);
303 void checkUserInterrupt();
304
305 bool isMainThread();
306 void initMainThread(MainThreadFunction f);
307
308 class IgnoreInterruptsScope : boost::noncopyable
309 {
310 public:
311 IgnoreInterruptsScope();
312 virtual ~IgnoreInterruptsScope();
313 private:
314 bool previousInterruptsSuspended_;
315 boost::scoped_ptr<core::system::SignalBlocker> pSignalBlocker_;
316 };
317
318 // returns true if the global context is on the top (i.e. the context stack is
319 // empty and we're not debugging)
320 bool atTopLevelContext();
321
322 // create a scope for disabling debugging while evaluating an expression in a
323 // given environment--this is needed to protect internal functions from being
324 // stepped into when we execute them while the user is stepping while
325 // debugging. R does this itself for expressions entered at the Browse prompt,
326 // but we need to do it manually.
327 // Discussion here: https://bugs.r-project.org/bugzilla/show_bug.cgi?id=15770
328 class DisableDebugScope : boost::noncopyable
329 {
330 public:
331 DisableDebugScope(SEXP env);
332 virtual ~DisableDebugScope();
333
334 private:
335 int rdebug_; // stored debug flag
336 SEXP env_; // debug environment (or NULL if not debugging)
337 };
338
339
340 class InterruptException {};
341
342 // track whether the session was interrupted
343 bool getWasInterrupted();
344 void setWasInterrupted(bool wasInterrupted);
345
346 } // namespace exec
347 } // namespace r
348 } // namespace rstudio
349
350
351 #endif // R_R_EXEC_HPP
352
353