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,93 @@ +//===------------------ PointerSortingChecker.cpp -------------------------===// +// +// 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 which checks for non-determinism +// caused due to sorting container with pointer-like elements. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" + +using namespace clang; +using namespace ento; +using namespace ast_matchers; + +namespace { + +// ID of a node at which the diagnostic would be emitted. +const char *WarnAtNode = "sort"; + +class PointerSortingChecker : public Checker { +public: + void checkASTCodeBody(const Decl *D, + AnalysisManager &AM, + BugReporter &BR) const; +}; + +static void emitDiagnostics(const BoundNodes &Match, const Decl *D, + BugReporter &BR, AnalysisManager &AM, + const PointerSortingChecker *Checker) { + auto *ADC = AM.getAnalysisDeclContext(D); + + const auto *MarkedStmt = Match.getNodeAs(WarnAtNode); + assert(MarkedStmt); + + auto Range = MarkedStmt->getSourceRange(); + auto Location = PathDiagnosticLocation::createBegin(MarkedStmt, + BR.getSourceManager(), + ADC); + std::string Diagnostics; + llvm::raw_string_ostream OS(Diagnostics); + OS << "Sorting pointer-like keys can result in non-deterministic ordering"; + + BR.EmitBasicReport(ADC->getDecl(), Checker, + "Sorting of pointer-like keys", "Non-determinism", + OS.str(), Location, Range); +} + +auto callsName(const char *FunctionName) -> decltype(callee(functionDecl())) { + return callee(functionDecl(hasName(FunctionName))); +} + +auto matchSortWithPointers() -> decltype(decl()) { + auto PointsToPointerM = hasType(cxxRecordDecl(has( + fieldDecl(hasType( + pointsTo(pointerType()) + )) + ))); + + auto SortFuncM = stmt(callExpr(allOf( + callsName("std::sort"), + argumentCountIs(2), + hasArgument(0, PointsToPointerM))) + ).bind(WarnAtNode); + + return decl(forEachDescendant(SortFuncM)); +} + +void PointerSortingChecker::checkASTCodeBody(const Decl *D, + AnalysisManager &AM, + BugReporter &BR) const { + auto MatcherM = matchSortWithPointers(); + + auto Matches = match(MatcherM, *D, AM.getASTContext()); + for (BoundNodes Match : Matches) + emitDiagnostics(Match, D, BR, AM, this); +} + +} // end of anonymous namespace + +void ento::registerPointerSortingChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} Index: test/Analysis/ptr-sort.cpp =================================================================== --- /dev/null +++ test/Analysis/ptr-sort.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.nondeterminism.PointerSorting %s -analyzer-output=text -verify + +#include "Inputs/system-header-simulator-cxx.h" +namespace std { + template + void sort (RandomIt first, RandomIt last); + + template + void sort (RandomIt first, RandomIt last, Compare comp); +} +using namespace std; + +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(), true); // no-warning + + std::sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like keys can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] + // expected-note@-1 {{Sorting pointer-like keys can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] + + sort(V2.begin(), V2.end()); // expected-warning {{Sorting pointer-like keys can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] + // expected-note@-1 {{Sorting pointer-like keys can result in non-deterministic ordering}} [alpha.nondeterminism.PointerSorting] +}