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