Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upRewrite no_init() and other functions to reduce false positives #893
Conversation
Codecov Report
@@ Coverage Diff @@
## master #893 +/- ##
==========================================
+ Coverage 90.14% 90.15% +<.01%
==========================================
Files 71 71
Lines 3279 3282 +3
==========================================
+ Hits 2956 2959 +3
Misses 323 323
Continue to review full report at Codecov.
|
| @@ -25,12 +25,16 @@ namespace Rcpp{ | |||
| return x ; | |||
| } | |||
|
|
|||
| inline SEXP Rcpp_unprotect(int i){ | |||
eddelbuettel
Aug 18, 2018
Member
This function wants to be void or else g++ yells at you.
This function wants to be void or else g++ yells at you.
krlmlr
Aug 19, 2018
Author
Contributor
Thanks, done.
Thanks, done.
| operator Vector<RTYPE, StoragePolicy>() const { | ||
| return Rf_allocVector(RTYPE, size) ; | ||
| template <int RTYPE> | ||
| operator Vector<RTYPE, PreserveStorage>() const { |
kevinushey
Aug 18, 2018
Contributor
Why change the template parameters here? Do we need separate operators for each of the storage policies?
Why change the template parameters here? Do we need separate operators for each of the storage policies?
krlmlr
Aug 19, 2018
Author
Contributor
I think no_init() should always return a properly protected vector, that's why I removed this template parameter. But I'm not sure.
I think no_init() should always return a properly protected vector, that's why I removed this template parameter. But I'm not sure.
kevinushey
Aug 20, 2018
Contributor
The intention is that the caller can indicate whether they want protection or want -- by default, they get a protected vector; if they don't want one then they can request conversion to the NoPreserveStorage variant.
IIUC, since this function was previously returning a raw SEXP, the associated constructor would be called on that return value and that constructor would take care of preserving the underlying storage when required.
The intention is that the caller can indicate whether they want protection or want -- by default, they get a protected vector; if they don't want one then they can request conversion to the NoPreserveStorage variant.
IIUC, since this function was previously returning a raw SEXP, the associated constructor would be called on that return value and that constructor would take care of preserving the underlying storage when required.
eddelbuettel
Aug 20, 2018
Member
As I recall, the "feature" of no_init() was to save the handful of cycles needed to set the memory to zero, but not to alter anything on protection or lack thereof.
As I recall, the "feature" of no_init() was to save the handful of cycles needed to set the memory to zero, but not to alter anything on protection or lack thereof.
krlmlr
Aug 21, 2018
Author
Contributor
no_init() effectively returns an uninitialized vector (via constructing a temporary and calling operator Vector<...>() on it). To be on the very safe side, this uninitialized vector needs to be protected during its lifetime; the protection state of the target is of no relevance. This corner case is perhaps irrelevant.
Vector::Vector(SEXP) seems to coerce (in the very generic case, not affecting us, but may be hard to tell for rchk). Maybe rchk thinks (or sees) that this constructor is involved in Vector<...> x = no_init(...)?
Happy to revert to the original implementation (with the second template parameter), but I'll check first if rchk eats this.
no_init() effectively returns an uninitialized vector (via constructing a temporary and calling operator Vector<...>() on it). To be on the very safe side, this uninitialized vector needs to be protected during its lifetime; the protection state of the target is of no relevance. This corner case is perhaps irrelevant.
Vector::Vector(SEXP) seems to coerce (in the very generic case, not affecting us, but may be hard to tell for rchk). Maybe rchk thinks (or sees) that this constructor is involved in Vector<...> x = no_init(...)?
Happy to revert to the original implementation (with the second template parameter), but I'll check first if rchk eats this.
|
My understanding is that rchk was primarily designed to diagnose C rather than C++ code. I would prefer not making these kinds of changes just to appease the tool unless we really have a good reason. |
|
The proposed changes reduce false positives reported by The Code that relies entirely on Rcpp's vector classes doesn't benefit much from |
|
A quick check at GitHub searching 'user:cran no_init' shows that there are about a handful of packages using A reverse-depends run seems to suggest no new issues (package 'vapour' came up failing but I also see the same issue for macOS at its CRAN checks so this may not be us). What about |
|
Thanks. I'll address the matrix case and also try to simplify the code more. I still think we need to return an object with protection, if we keep the I don't understand "keep |
Since CRAN is enforcing these checks I agree we should do what we can to reduce false positives. |
| @@ -243,7 +243,7 @@ namespace internal { | |||
| inline bool is_Rcpp_eval_call(SEXP expr) { | |||
| SEXP sys_calls_symbol = Rf_install("sys.calls"); | |||
| SEXP identity_symbol = Rf_install("identity"); | |||
| SEXP identity_fun = Rf_findFun(identity_symbol, R_BaseEnv); | |||
| Shield<SEXP> identity_fun(Rf_findFun(identity_symbol, R_BaseEnv)); | |||
| SEXP tryCatch_symbol = Rf_install("tryCatch"); | |||
kevinushey
Aug 20, 2018
Contributor
Does rchk warn about the unprotected use of 'install' here?
Does rchk warn about the unprotected use of 'install' here?
eddelbuettel
Aug 21, 2018
Member
So should the PR cover that too then?
So should the PR cover that too then?
krlmlr
Aug 21, 2018
Author
Contributor
I was confused. No, rchk knows that the Rf_install() result is protected already, but Rf_install() could be an allocation (in theory) which could clean up the result of Rf_findFun().
I was confused. No, rchk knows that the Rf_install() result is protected already, but Rf_install() could be an allocation (in theory) which could clean up the result of Rf_findFun().
| operator Vector<RTYPE, PreserveStorage>() const { | ||
| // Explicitly protect temporary vector to avoid false positive | ||
| // with rchk (#892) | ||
| SEXP x = PROTECT(Rf_allocVector(RTYPE, size)); |
kevinushey
Aug 20, 2018
Contributor
What about using Shield<SEXP> here rather than raw protect / unprotect?
What about using Shield<SEXP> here rather than raw protect / unprotect?
krlmlr
Aug 21, 2018
Author
Contributor
Need to check if rchk is satisfied.
Need to check if rchk is satisfied.
|
Thanks for coming back to this -- looks pretty good now (though it is early here and the coffee may not have settled ... ;-) One thing still missing is the Matrix case on |
|
Thanks for the heads-up, I forgot. (Need to wait for the checks.) |
|
Err, don't you test locally before sending a commit ? |
|
Guilty as charged. |
|
I may not be entirely innocent of the practice either but I hate the red outcomes with such a vengeance that I try avoid this. Nice use of |
|
I will set up another reverse-depends check. Not expecting any trouble. Should be ready to merge. @kevinushey @jjallaire @thirdwing @nathan-russell and anybody else: Comments? Concerns? |
|
I canceled and restarted that one, and (of course) just after I canceled it completed. It had |
|
Thanks. Looks super-green now. |
|
No new issue in level-one reverse depends check, results at RcppCore/rcpp-logs@1d9d5fa |
Reference: #892.