From: Ted Kremenek Date: Thu, 11 Oct 2012 20:58:18 +0000 (+0000) Subject: Switch over to BodyFarm implementation of OSAtomicCompareAndSwap and X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=48fa1361505c51cdc5e78deffdbdd7c334cca5d0;p=clang Switch over to BodyFarm implementation of OSAtomicCompareAndSwap and objc_atomicCompareAndSwap. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165743 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 3dcbfb927e..9a04a82675 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Decl.h" +#include "clang/AST/ExprObjC.h" #include "BodyFarm.h" using namespace clang; @@ -49,6 +50,13 @@ public: /// Create a new BinaryOperator representing a simple assignment. BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); + /// Create a new BinaryOperator representing a comparison. + BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, + BinaryOperator::Opcode Op); + + /// Create a new compound stmt using the provided statements. + CompoundStmt *makeCompound(ArrayRef); + /// Create a new DeclRefExpr for the referenced variable. DeclRefExpr *makeDeclRefExpr(const VarDecl *D); @@ -58,9 +66,18 @@ public: /// Create an implicit cast for an integer conversion. ImplicitCastExpr *makeIntegralCast(const Expr *Arg, QualType Ty); + /// Create an implicit cast to a builtin boolean type. + ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); + // Create an implicit cast for lvalue-to-rvaluate conversions. ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); + /// Create an Objective-C bool literal. + ObjCBoolLiteralExpr *makeObjCBool(bool Val); + + /// Create a Return statement. + ReturnStmt *makeReturn(const Expr *RetVal); + private: ASTContext &C; }; @@ -73,6 +90,24 @@ BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, OK_Ordinary, SourceLocation(), false); } +BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, + BinaryOperator::Opcode Op) { + assert(BinaryOperator::isLogicalOp(Op) || + BinaryOperator::isComparisonOp(Op)); + return new (C) BinaryOperator(const_cast(LHS), + const_cast(RHS), + Op, + C.getLogicalOperationType(), + VK_RValue, + OK_Ordinary, SourceLocation(), false); +} + +CompoundStmt *ASTMaker::makeCompound(ArrayRef Stmts) { + return new (C) CompoundStmt(C, const_cast(Stmts.data()), + Stmts.size(), + SourceLocation(), SourceLocation()); +} + DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { DeclRefExpr *DR = DeclRefExpr::Create(/* Ctx = */ C, @@ -101,6 +136,20 @@ ImplicitCastExpr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { const_cast(Arg), 0, VK_RValue); } +ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { + return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, + const_cast(Arg), 0, VK_RValue); +} + +ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { + QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; + return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); +} + +ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { + return new (C) ReturnStmt(SourceLocation(), const_cast(RetVal), 0); +} + //===----------------------------------------------------------------------===// // Creation functions for faux ASTs. //===----------------------------------------------------------------------===// @@ -163,9 +212,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { // (3) Create the compound statement. Stmt *Stmts[2]; Stmts[0] = B; - Stmts[1] = CE; - CompoundStmt *CS = new (C) CompoundStmt(C, Stmts, 2, SourceLocation(), - SourceLocation()); + Stmts[1] = CE; + CompoundStmt *CS = M.makeCompound(ArrayRef(Stmts, 2)); // (4) Create the 'if' condition. ImplicitCastExpr *LValToRval = @@ -213,6 +261,71 @@ static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { return CE; } +static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) +{ + // There are exactly 3 arguments. + if (D->param_size() != 3) + return 0; + + // Body for: + // if (oldValue == *theValue) { + // *theValue = newValue; + // return YES; + // } + // else return NO; + + const ParmVarDecl *OldValue = D->getParamDecl(0); + QualType OldValueTy = OldValue->getType(); + + const ParmVarDecl *NewValue = D->getParamDecl(1); + QualType NewValueTy = NewValue->getType(); + + assert(OldValueTy == NewValueTy); + + const ParmVarDecl *TheValue = D->getParamDecl(2); + QualType TheValueTy = TheValue->getType(); + const PointerType *PT = TheValueTy->getAs(); + if (!PT) + return 0; + QualType PointeeTy = PT->getPointeeType(); + + ASTMaker M(C); + // Construct the comparison. + Expr *Comparison = + M.makeComparison( + M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), + M.makeLvalueToRvalue( + M.makeDereference( + M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), + PointeeTy), + PointeeTy), + BO_EQ); + + // Construct the body of the IfStmt. + Stmt *Stmts[2]; + Stmts[0] = + M.makeAssignment( + M.makeDereference( + M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), + PointeeTy), + M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), + NewValueTy); + Stmts[1] = + M.makeReturn(M.makeIntegralCastToBoolean(M.makeObjCBool(true))); + CompoundStmt *Body = M.makeCompound(ArrayRef(Stmts, 2)); + + // Construct the else clause. + Stmt *Else = + M.makeReturn(M.makeIntegralCastToBoolean(M.makeObjCBool(false))); + + /// Construct the If. + Stmt *If = + new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body, + SourceLocation(), Else); + + return If; +} + Stmt *BodyFarm::getBody(const FunctionDecl *D) { D = D->getCanonicalDecl(); @@ -228,17 +341,21 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { StringRef Name = D->getName(); if (Name.empty()) return 0; - - FunctionFarmer FF = - llvm::StringSwitch(Name) - .Case("dispatch_sync", create_dispatch_sync) - .Case("dispatch_once", create_dispatch_once) - .Default(NULL); - - if (FF) { - Val = FF(C, D); + + FunctionFarmer FF; + + if (Name.startswith("OSAtomicCompareAndSwap") || + Name.startswith("objc_atomicCompareAndSwap")) { + FF = create_OSAtomicCompareAndSwap; + } + else { + FF = llvm::StringSwitch(Name) + .Case("dispatch_sync", create_dispatch_sync) + .Case("dispatch_once", create_dispatch_once) + .Default(NULL); } + if (FF) { Val = FF(C, D); } return Val.getValue(); } diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp index 81e4f0dcf2..6cdd9a5925 100644 --- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp @@ -212,5 +212,5 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE, } void ento::registerOSAtomicChecker(CheckerManager &mgr) { - mgr.registerChecker(); + // mgr.registerChecker(); }