-
-
Notifications
You must be signed in to change notification settings - Fork 208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite 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){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function wants to be void
or else g++
yells at you.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can cherry-pick it from 0df99c8
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, done.
inst/include/Rcpp/vector/no_init.h
Outdated
operator Vector<RTYPE, StoragePolicy>() const { | ||
return Rf_allocVector(RTYPE, size) ; | ||
template <int RTYPE> | ||
operator Vector<RTYPE, PreserveStorage>() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change the template parameters here? Do we need separate operators for each of the storage policies?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think no_init()
should always return a properly protected vector, that's why I removed this template parameter. But I'm not sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does rchk
warn about the unprotected use of 'install' here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So should the PR cover that too then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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()
.
inst/include/Rcpp/vector/no_init.h
Outdated
operator Vector<RTYPE, PreserveStorage>() const { | ||
// Explicitly protect temporary vector to avoid false positive | ||
// with rchk (#892) | ||
SEXP x = PROTECT(Rf_allocVector(RTYPE, size)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using Shield<SEXP>
here rather than raw protect / unprotect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.