Bug 1699844 - Add an escape hatch for the refcounted inside lambda checker. r=andi

Allow using the MOZ_KnownLive function to get around it.

Use case is the following: I have an std::function member variable, and I want
that member to be able to capture `this`.

Using a strong reference creates a cycle and thus would leak. I know `this` to
always outlive the member, so it is fine to use a weak capture there.

Differential Revision: https://phabricator.services.mozilla.com/D111850
This commit is contained in:
Emilio Cobos Álvarez 2021-04-14 19:12:02 +00:00
parent 3bbb2fccca
commit 80439edf68
3 changed files with 23 additions and 5 deletions

View File

@ -36,6 +36,18 @@ void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc,
diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Note);
}
static bool IsKnownLive(const VarDecl *Var) {
const Stmt *Init = Var->getInit();
if (!Init) {
return false;
}
if (auto *Call = dyn_cast<CallExpr>(Init)) {
const FunctionDecl *Callee = Call->getDirectCallee();
return Callee && Callee->getName() == "MOZ_KnownLive";
}
return false;
}
void RefCountedInsideLambdaChecker::check(
const MatchFinder::MatchResult &Result) {
static DenseSet<const CXXRecordDecl *> CheckedDecls;
@ -107,11 +119,11 @@ void RefCountedInsideLambdaChecker::check(
// pointers.
for (const LambdaCapture &Capture : Lambda->captures()) {
if (Capture.capturesVariable()) {
QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
emitDiagnostics(Capture.getLocation(),
Capture.getCapturedVar()->getName(), Pointee);
const VarDecl *Var = Capture.getCapturedVar();
QualType Pointee = Var->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee) &&
!IsKnownLive(Var)) {
emitDiagnostics(Capture.getLocation(), Var->getName(), Pointee);
return;
}
}

View File

@ -1,3 +1,5 @@
#include <mozilla/StaticAnalysisFunctions.h>
#include <functional>
#define MOZ_STRONG_REF
#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit")))
@ -667,6 +669,9 @@ R::privateMethod() {
privateMethod();
});
std::function<void()>(
[instance = MOZ_KnownLive(this)]() { instance->privateMethod(); });
// It should be OK to go through `this` if we have captured a reference to it.
std::function<void()>([this, self]() {
this->method();

View File

@ -13,6 +13,7 @@
# endif
# define MOZ_CONSTEXPR
#else // __cplusplus
# include "mozilla/Attributes.h"
# define MOZ_CONSTEXPR constexpr
#endif
/*