Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1697 from rstudio/feature/external-ptr-suspend
Don't suspend sessions with external pointers (fixes #1696)
- Loading branch information
Showing
6 changed files
with
104 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,6 +112,66 @@ bool handleRBrowseEnv(const core::FilePath& filePath) | |
} | ||
} | ||
|
||
bool hasExternalPtr(SEXP obj, // environment to search for external pointers | ||
bool nullPtr, // whether to look for NULL pointers | ||
int level = 5) // maximum recursion depth (envs can have self-ref loops) | ||
{ | ||
// list the contents of this environment | ||
std::vector<r::sexp::Variable> vars; | ||
r::sexp::Protect rProtect; | ||
if (r::sexp::isPrimitiveEnvironment(obj)) | ||
{ | ||
// for simple environments, list the objects in the environment | ||
r::sexp::listEnvironment(obj, | ||
true, // include all values | ||
false, // don't include last dot | ||
&rProtect, &vars); | ||
} | ||
else if (TYPEOF(obj) == S4SXP) | ||
{ | ||
// for S4 objects, list the attributes (which correspond to slots) | ||
r::sexp::listNamedAttributes(obj, &rProtect, &vars); | ||
} | ||
|
||
// check for external pointers | ||
for (std::vector<r::sexp::Variable>::iterator it = vars.begin(); it != vars.end(); it++) | ||
{ | ||
if (r::sexp::isExternalPointer(it->second) && | ||
r::sexp::isNullExternalPointer(it->second) == nullPtr) | ||
{ | ||
return true; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
jmcphers
Author
Member
|
||
} | ||
|
||
if (r::sexp::isPrimitiveEnvironment(it->second) || TYPEOF(it->second) == S4SXP) | ||
{ | ||
// if this object is itself an environment, check it recursively for external pointers. | ||
// (we do this only if there's sufficient recursion depth remaining) | ||
if (level > 0 && hasExternalPtr(it->second, nullPtr, level - 1)) | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
SEXP rs_hasExternalPointer(SEXP objSEXP, SEXP nullSEXP) | ||
{ | ||
bool nullPtr = r::sexp::asLogical(nullSEXP); | ||
r::sexp::Protect protect; | ||
bool hasPtr = false; | ||
if (r::sexp::isExternalPointer(objSEXP)) | ||
{ | ||
// object is an external pointer itself | ||
hasPtr = r::sexp::isNullExternalPointer(objSEXP) == nullPtr; | ||
} | ||
else if (r::sexp::isPrimitiveEnvironment(objSEXP) || TYPEOF(objSEXP) == S4SXP) | ||
{ | ||
// object is an environment; check it for external pointers | ||
hasPtr = hasExternalPtr(objSEXP, nullPtr); | ||
} | ||
return r::sexp::create(hasPtr, &protect); | ||
} | ||
|
||
// Construct a simulated source reference from a context containing a | ||
// function being debugged, and either the context containing the current | ||
// invocation or a string containing the last debug ouput from R. | ||
|
@@ -944,6 +1004,12 @@ SEXP rs_isBrowserActive() | |
return r::sexp::create(s_browserActive, &protect); | ||
} | ||
|
||
bool isSuspendable() | ||
{ | ||
// suppress suspension if any object has a live external pointer; these can't be restored | ||
return !hasExternalPtr(R_GlobalEnv, false); | ||
} | ||
|
||
Error initialize() | ||
{ | ||
// store on the heap so that the destructor is never called (so we | ||
|
@@ -975,6 +1041,8 @@ Error initialize() | |
methodDef.numArgs = 3; | ||
r::routines::addCallMethod(methodDef); | ||
|
||
RS_REGISTER_CALL_METHOD(rs_hasExternalPointer, 2); | ||
|
||
// subscribe to events | ||
using boost::bind; | ||
using namespace session::module_context; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
It looks to me like the external ptr has to be NULL in order for the function to return TRUE (so we wouldn't actually catch "live" reticulate objects). Am I misreading the code?