Skip to content

Commit 4266522

Browse files
committedAug 4, 2014
Thread safety analysis: Add support for negative requirements, which are
capability expressions of the form !expr, and denote a capability that must not be held. llvm-svn: 214725
1 parent 0b2ebcb commit 4266522

File tree

5 files changed

+473
-285
lines changed

5 files changed

+473
-285
lines changed
 

‎clang/include/clang/Analysis/Analyses/ThreadSafety.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ enum ProtectedOperationKind {
3838
/// example, it is an error to write a variable protected by shared version of a
3939
/// mutex.
4040
enum LockKind {
41-
LK_Shared, ///< Shared/reader lock of a mutex.
41+
LK_Shared, ///< Shared/reader lock of a mutex.
4242
LK_Exclusive, ///< Exclusive/writer lock of a mutex.
43-
LK_Generic ///< Can be either Shared or Exclusive
43+
LK_Generic ///< Can be either Shared or Exclusive
4444
};
4545

4646
/// This enum distinguishes between different ways to access (read or write) a

‎clang/include/clang/Analysis/Analyses/ThreadSafetyCommon.h

+99-3
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,59 @@
2424

2525
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
2626
#include "clang/Analysis/Analyses/ThreadSafetyTIL.h"
27+
#include "clang/Analysis/Analyses/ThreadSafetyTraverse.h"
2728
#include "clang/Analysis/AnalysisContext.h"
2829
#include "clang/Basic/OperatorKinds.h"
2930

3031
#include <memory>
32+
#include <ostream>
33+
#include <sstream>
3134
#include <vector>
3235

3336

3437
namespace clang {
3538
namespace threadSafety {
3639

40+
41+
// Various helper functions on til::SExpr
42+
namespace sx {
43+
44+
inline bool equals(const til::SExpr *E1, const til::SExpr *E2) {
45+
return til::EqualsComparator::compareExprs(E1, E2);
46+
}
47+
48+
inline bool matches(const til::SExpr *E1, const til::SExpr *E2) {
49+
// We treat a top-level wildcard as the "univsersal" lock.
50+
// It matches everything for the purpose of checking locks, but not
51+
// for unlocking them.
52+
if (isa<til::Wildcard>(E1))
53+
return isa<til::Wildcard>(E2);
54+
if (isa<til::Wildcard>(E2))
55+
return isa<til::Wildcard>(E1);
56+
57+
return til::MatchComparator::compareExprs(E1, E2);
58+
}
59+
60+
inline bool partiallyMatches(const til::SExpr *E1, const til::SExpr *E2) {
61+
auto *PE1 = dyn_cast_or_null<til::Project>(E1);
62+
if (!PE1)
63+
return false;
64+
auto *PE2 = dyn_cast_or_null<til::Project>(E2);
65+
if (!PE2)
66+
return false;
67+
return PE1->clangDecl() == PE2->clangDecl();
68+
}
69+
70+
inline std::string toString(const til::SExpr *E) {
71+
std::stringstream ss;
72+
til::StdPrinter::print(E, ss);
73+
return ss.str();
74+
}
75+
76+
} // end namespace sx
77+
78+
79+
3780
// This class defines the interface of a clang CFG Visitor.
3881
// CFGWalker will invoke the following methods.
3982
// Note that methods are not virtual; the visitor is templatized.
@@ -206,6 +249,59 @@ class CFGWalker {
206249
};
207250

208251

252+
253+
254+
class CapabilityExpr {
255+
// TODO: move this back into ThreadSafety.cpp
256+
// This is specific to thread safety. It is here because
257+
// translateAttrExpr needs it, but that should be moved too.
258+
259+
private:
260+
const til::SExpr* CapExpr; //< The capability expression.
261+
bool Negated; //< True if this is a negative capability
262+
263+
public:
264+
CapabilityExpr(const til::SExpr *E, bool Neg) : CapExpr(E), Negated(Neg) {}
265+
266+
const til::SExpr* sexpr() const { return CapExpr; }
267+
bool negative() const { return Negated; }
268+
269+
CapabilityExpr operator!() const {
270+
return CapabilityExpr(CapExpr, !Negated);
271+
}
272+
273+
bool equals(const CapabilityExpr &other) const {
274+
return (Negated == other.Negated) && sx::equals(CapExpr, other.CapExpr);
275+
}
276+
277+
bool matches(const CapabilityExpr &other) const {
278+
return (Negated == other.Negated) && sx::matches(CapExpr, other.CapExpr);
279+
}
280+
281+
bool matchesUniv(const CapabilityExpr &CapE) const {
282+
return isUniversal() || matches(CapE);
283+
}
284+
285+
bool partiallyMatches(const CapabilityExpr &other) const {
286+
return (Negated == other.Negated) &&
287+
sx::partiallyMatches(CapExpr, other.CapExpr);
288+
}
289+
290+
std::string toString() const {
291+
if (Negated)
292+
return "!" + sx::toString(CapExpr);
293+
return sx::toString(CapExpr);
294+
}
295+
296+
bool shouldIgnore() const { return CapExpr == nullptr; }
297+
298+
bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
299+
300+
bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
301+
};
302+
303+
304+
209305
// Translate clang::Expr to til::SExpr.
210306
class SExprBuilder {
211307
public:
@@ -242,10 +338,10 @@ class SExprBuilder {
242338

243339
// Translate a clang expression in an attribute to a til::SExpr.
244340
// Constructs the context from D, DeclExp, and SelfDecl.
245-
til::SExpr *translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
246-
const Expr *DeclExp, VarDecl *SelfDecl=nullptr);
341+
CapabilityExpr translateAttrExpr(const Expr *AttrExp, const NamedDecl *D,
342+
const Expr *DeclExp, VarDecl *SelfD=nullptr);
247343

248-
til::SExpr *translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
344+
CapabilityExpr translateAttrExpr(const Expr *AttrExp, CallingContext *Ctx);
249345

250346
// Translate a clang statement or expression to a TIL expression.
251347
// Also performs substitution of variables; Ctx provides the context.

0 commit comments

Comments
 (0)
Please sign in to comment.