Index: include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- include/clang/StaticAnalyzer/Checkers/Checkers.td +++ include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -94,6 +94,8 @@ def CloneDetectionAlpha : Package<"clone">, InPackage, Hidden; +def NonDeterminismAlpha : Package<"nondeterminism">, InPackage, Hidden; + //===----------------------------------------------------------------------===// // Core Checkers. //===----------------------------------------------------------------------===// @@ -825,3 +827,15 @@ DescFile<"UnixAPIChecker.cpp">; } // end optin.portability + +//===----------------------------------------------------------------------===// +// NonDeterminism checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = NonDeterminismAlpha in { + +def PointerSortingChecker : Checker<"PointerSorting">, + HelpText<"Checks for non-determinism caused by sorting of pointer-like keys">, + DescFile<"PointerSortingChecker.cpp">; + +} // end alpha.nondeterminism Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -74,6 +74,7 @@ ObjCUnusedIVarsChecker.cpp PaddingChecker.cpp PointerArithChecker.cpp + PointerSortingChecker.cpp PointerSubChecker.cpp PthreadLockChecker.cpp RetainCountChecker.cpp Index: lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp =================================================================== --- /dev/null +++ lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp @@ -0,0 +1,123 @@ +//=== PointerSortingChecker.cpp - Pointer Sorting Checker ---*- C++ -*---=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines PointerSortingChecker, a builtin checker that checks for +// non-determinism caused by sorting of pointer-like keys. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" + +#define DEBUG_TYPE "check-pointer-sort" + +using namespace clang; +using namespace ento; + +namespace { + +// PointerSortingVisitor class. +class PointerSortingVisitor : public StmtVisitor { + BugReporter &BR; + const CheckerBase *Checker; + AnalysisDeclContext* AC; + +private: + void reportPointerSortingDiagnostic(CallExpr *CE); + +public: + PointerSortingVisitor(BugReporter &br, + const CheckerBase *checker, + AnalysisDeclContext *ac) + : BR(br), Checker(checker), AC(ac) {} + void VisitStmt(Stmt *S) { VisitChildren(S); } + void VisitChildren(Stmt *S); + void VisitCallExpr(CallExpr *CE); +}; +} + +void PointerSortingVisitor::VisitChildren(Stmt *S) { + for (Stmt *Child : S->children()) + if (Child) + Visit(Child); +} + +void PointerSortingVisitor::reportPointerSortingDiagnostic(CallExpr *CE) { + SmallString<64> buf; + llvm::raw_svector_ostream os(buf); + os << "Non-deterministic sorting of pointer-like keys"; + const char *BugType = "Pointer Sorting"; + + SmallVector ranges; + ranges.push_back(CE->getSourceRange()); + + PathDiagnosticLocation CELoc = + PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); + BR.EmitBasicReport(AC->getDecl(), Checker, BugType, + "Non-determinism", os.str(), CELoc, ranges); +} + +// VisitCallExpr - This looks for calls to std::sort for containers with +// pointer-like keys. +void PointerSortingVisitor::VisitCallExpr(CallExpr *CE) { + // FIXME: Currently we only report std::sort which uses the default comparator + // to sort a container with pointer-like keys. + if (CE->getNumArgs() != 2) + return; + + const FunctionDecl *FD = CE->getDirectCallee(); + if (!FD) + return; + + if (!AnalysisDeclContext::isInStdNamespace(FD)) + return; + + IdentifierInfo *II = FD->getIdentifier(); + if (!II) + return; + + if (!II->getName().equals("sort")) + return; + + const QualType IterTy = CE->getArg(0)->getType(); + const RecordDecl *RD = + IterTy->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); + + if (RD->field_empty()) + return; + + const FieldDecl *I = *RD->field_begin(); + if (!I->getType()->getPointeeType()->isPointerType()) + return; + + reportPointerSortingDiagnostic(CE); +} + +//===----------------------------------------------------------------------===// +// PointerSortingChecker +//===----------------------------------------------------------------------===// + +namespace { +class PointerSortingChecker : public Checker { +public: + void checkASTCodeBody(const Decl *D, + AnalysisManager& mgr, + BugReporter &BR) const { + PointerSortingVisitor Visitor(BR, this, mgr.getAnalysisDeclContext(D)); + Visitor.Visit(D->getBody()); + } +}; +} + +void ento::registerPointerSortingChecker(CheckerManager &mgr) { + mgr.registerChecker(); +} Index: test/Analysis/ptr-sort.cpp =================================================================== --- /dev/null +++ test/Analysis/ptr-sort.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.nondeterminism.PointerSorting %s -analyzer-output=text -verify + +#include "Inputs/system-header-simulator-cxx.h" + +namespace std { + template + void sort(RandomAccessIterator first, RandomAccessIterator last); +} + +void PointerSorting() { + int a = 1, b = 2; + + std::vector V1 = {a, b}; + std::sort(V1.begin(), V1.end()); // no-warning + + std::vector V2 = {&a, &b}; + std::sort(V2.begin(), V2.end()); // expected-warning {{Non-deterministic sorting of pointer-like keys}} [alpha.nondeterminism.PointerSorting] + // expected-note@-1 {{Non-deterministic sorting of pointer-like keys}} [alpha.nondeterminism.PointerSorting] +}