Skip to content

Commit

Permalink
ts: try to warn on unmatched attributes...
Browse files Browse the repository at this point in the history
  • Loading branch information
elmarco committed Jul 4, 2017
1 parent 27dec58 commit bac9428
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/clang/Analysis/Analyses/ThreadSafety.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ class ThreadSafetyHandler {
/// Warn that there is a cycle in acquired_before/after dependencies.
virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {}

virtual void handleUnmatchedAttrs(SourceLocation Loc) {}

/// Called by the analysis when starting analysis of a function.
/// Used to issue suggestions for changes to annotations.
virtual void enterFunction(const FunctionDecl *FD) {}
Expand Down
4 changes: 3 additions & 1 deletion include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2969,7 +2969,9 @@ def warn_acquired_before : Warning<
def warn_acquired_before_after_cycle : Warning<
"Cycle in acquired_before/after dependencies, starting with '%0'">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;

def warn_unmatched_attrs : Warning<
"Unmached attributes">,
InGroup<ThreadSafetyAnalysis>, DefaultIgnore;

// Thread safety warnings negative capabilities
def warn_acquire_requires_negative_cap : Warning<
Expand Down
1 change: 1 addition & 0 deletions include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -9311,6 +9311,7 @@ class Sema {
AssignConvertType CheckAssignmentConstraints(SourceLocation Loc,
QualType LHSType,
QualType RHSType);
AssignConvertType checkAttr(Decl *LHS, Decl *RHS);

/// Check assignment constraints and optionally prepare for a conversion of
/// the RHS to the LHS type. The conversion is prepared for if ConvertRHS
Expand Down
91 changes: 91 additions & 0 deletions lib/Analysis/ThreadSafety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1703,11 +1703,30 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
auto *VD = clang::dyn_cast<clang::VarDecl>(D);
auto *T = VD->getType().getTypePtr();
auto *TT = T->getAs<TypedefType>();
if (!TT)
return;
D = TT->getDecl();
} else if (D->getKind() == clang::Decl::ParmVar) {
auto *PV = clang::dyn_cast<clang::ParmVarDecl>(D);
auto *T = PV->getType().getTypePtr();
auto *TT = T->getAs<TypedefType>();
if (!TT && T->isPointerType()) {
T = T->getPointeeType().getTypePtr();
TT = T->getAs<TypedefType>();
}
if (!TT)
return;
D = TT->getDecl();
} else if (D->getKind() == clang::Decl::Field) {
auto *F = clang::dyn_cast<clang::FieldDecl>(D);
auto *T = F->getType().getTypePtr();
auto *TT = T->getAs<TypedefType>();
if (!TT && T->isPointerType()) {
T = T->getPointeeType().getTypePtr();
TT = T->getAs<TypedefType>();
}
if (!TT)
return;
D = TT->getDecl();
}

Expand Down Expand Up @@ -1876,6 +1895,47 @@ void BuildLockset::VisitCastExpr(CastExpr *CE) {
checkAccess(CE->getSubExpr(), AK_Read);
}

static const Decl *getDecl(const Type *T)
{
const TypedefType *TT;

if (T->isIncompleteArrayType() || T->isArrayType()) {
return getDecl(T->getArrayElementTypeNoTypeQual());
}
if (T->isPointerType()) {
T = T->getPointeeType().getTypePtr();
}

TT = T->getAs<TypedefType>();
if (!TT)
return NULL;

return TT->getDecl();
}

static bool hasRC(const Decl *D)
{
if (!D)
return false;

if (D->hasAttr<RequiresCapabilityAttr>())
return true;

if (D->getKind() == clang::Decl::Var) {
auto *F = clang::dyn_cast<clang::VarDecl>(D);
return hasRC(getDecl(F->getType().getTypePtr()));
}
if (D->getKind() == clang::Decl::Field) {
auto *F = clang::dyn_cast<clang::FieldDecl>(D);
return hasRC(getDecl(F->getType().getTypePtr()));
}
if (D->getKind() == clang::Decl::ParmVar) {
auto *PV = clang::dyn_cast<clang::ParmVarDecl>(D);
return hasRC(getDecl(PV->getType().getTypePtr()));
}

return false;
}

void BuildLockset::VisitCallExpr(CallExpr *Exp) {
bool ExamineArgs = true;
Expand Down Expand Up @@ -1968,6 +2028,37 @@ void BuildLockset::VisitCallExpr(CallExpr *Exp) {
QualType Qt = Pvd->getType();
if (Qt->isReferenceType())
checkAccess(Arg, AK_Read, POK_PassByRef);

if (hasRC(Pvd) != hasRC(getValueDecl(Arg))) {
Analyzer->Handler.handleUnmatchedAttrs(Arg->getExprLoc());
}
// auto *T = Qt.getTypePtr();
// if (!T)
// continue;
// auto *TT = T->getAs<TypedefType>();
// if (!TT && T->isPointerType()) {
// T = T->getPointeeType().getTypePtr();
// TT = T->getAs<TypedefType>();
// }
// if (!TT)
// continue;
// auto *D = TT->getDecl();

// SmallVector<const RequiresCapabilityAttr *, 4> PRequiresCap, ARequiresCap;
// for (const auto *A: D->specific_attrs<RequiresCapabilityAttr>()) {
// PRequiresCap.push_back(A);
// }

// const ValueDecl *VD = getValueDecl(Arg);
// if (!VD)
// continue;
// for (const auto *A: VD->specific_attrs<RequiresCapabilityAttr>()) {
// ARequiresCap.push_back(A);
// }

// if (ARequiresCap.size() != PRequiresCap.size()) {
// Analyzer->Handler.handleUnmatchedAttrs(Exp->getExprLoc());
// }
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/AnalysisBasedWarnings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler {
Warnings.emplace_back(std::move(Warning), getNotes());
}

void handleUnmatchedAttrs(SourceLocation Loc) override {
PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unmatched_attrs));
Warnings.emplace_back(std::move(Warning), getNotes());
}

void enterFunction(const FunctionDecl* FD) override {
CurrentFunction = FD;
}
Expand Down
52 changes: 52 additions & 0 deletions lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7892,6 +7892,58 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
return Compatible;
}

static const Decl *getDecl(const Type *T)
{
const TypedefType *TT;

if (T->isIncompleteArrayType() || T->isArrayType()) {
return getDecl(T->getArrayElementTypeNoTypeQual());
}
if (T->isPointerType()) {
T = T->getPointeeType().getTypePtr();
}

TT = T->getAs<TypedefType>();
if (!TT)
return NULL;

return TT->getDecl();
}

static bool hasRC(const Decl *D)
{
if (!D)
return false;

if (D->hasAttr<RequiresCapabilityAttr>())
return true;

if (D->getKind() == clang::Decl::Var) {
auto *F = clang::dyn_cast<clang::VarDecl>(D);
return hasRC(getDecl(F->getType().getTypePtr()));
}
if (D->getKind() == clang::Decl::Field) {
auto *F = clang::dyn_cast<clang::FieldDecl>(D);
return hasRC(getDecl(F->getType().getTypePtr()));
}
if (D->getKind() == clang::Decl::ParmVar) {
auto *PV = clang::dyn_cast<clang::ParmVarDecl>(D);
return hasRC(getDecl(PV->getType().getTypePtr()));
}

return false;
}

Sema::AssignConvertType
Sema::checkAttr(Decl *LHS, Decl *RHS)
{
if (hasRC(LHS) != hasRC(RHS))
return Incompatible;

return Compatible;
}


Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
bool Diagnose,
Expand Down
12 changes: 12 additions & 0 deletions lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7061,6 +7061,18 @@ InitializationSequence::Perform(Sema &S,
Sema::AssignConvertType ConvTy =
S.CheckSingleAssignmentConstraints(Step->Type, Result, true,
Entity.getKind() == InitializedEntity::EK_Parameter_CF_Audited);

auto *E = Result.get();
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
E = UO->getSubExpr();
}
auto *RHS = E->getReferencedDeclOfCallee();
auto *LHS = Entity.getDecl();
if (!LHS && Entity.getParent()) {
LHS = Entity.getParent()->getDecl();
}
if (S.checkAttr(LHS, RHS) == Sema::Incompatible)
ConvTy = Sema::Incompatible;
if (Result.isInvalid())
return ExprError();
CurInit = Result;
Expand Down

0 comments on commit bac9428

Please sign in to comment.