1 //===--- ProperlySeededRandomGeneratorCheck.cpp - clang-tidy---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "ProperlySeededRandomGeneratorCheck.h" 11 #include "clang/AST/ASTContext.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 13 #include "llvm/ADT/STLExtras.h" 14 15 using namespace clang::ast_matchers; 16 17 namespace clang { 18 namespace tidy { 19 namespace cert { 20 21 ProperlySeededRandomGeneratorCheck::ProperlySeededRandomGeneratorCheck( 22 StringRef Name, ClangTidyContext *Context) 23 : ClangTidyCheck(Name, Context), 24 RawDisallowedSeedTypes( 25 Options.get("DisallowedSeedTypes", "time_t,std::time_t")) { 26 StringRef(RawDisallowedSeedTypes).split(DisallowedSeedTypes, ','); 27 } 28 29 void ProperlySeededRandomGeneratorCheck::storeOptions( 30 ClangTidyOptions::OptionMap &Opts) { 31 Options.store(Opts, "DisallowedSeedTypes", RawDisallowedSeedTypes); 32 } 33 34 void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) { 35 auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName( 36 "::std::linear_congruential_engine", "::std::mersenne_twister_engine", 37 "::std::subtract_with_carry_engine", "::std::discard_block_engine", 38 "::std::independent_bits_engine", "::std::shuffle_order_engine")); 39 auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType( 40 recordType(hasDeclaration(RandomGeneratorEngineDecl)))); 41 42 // std::mt19937 engine; 43 // engine.seed(); 44 // ^ 45 // engine.seed(1); 46 // ^ 47 // const int x = 1; 48 // engine.seed(x); 49 // ^ 50 Finder->addMatcher( 51 cxxMemberCallExpr( 52 has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)), 53 member(hasName("seed")), 54 unless(hasDescendant(cxxThisExpr()))))) 55 .bind("seed"), 56 this); 57 58 // std::mt19937 engine; 59 // ^ 60 // std::mt19937 engine(1); 61 // ^ 62 // const int x = 1; 63 // std::mt19937 engine(x); 64 // ^ 65 Finder->addMatcher( 66 cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor"), this); 67 68 // srand(); 69 // ^ 70 // const int x = 1; 71 // srand(x); 72 // ^ 73 Finder->addMatcher( 74 callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand")))) 75 .bind("srand"), 76 this); 77 } 78 79 void ProperlySeededRandomGeneratorCheck::check( 80 const MatchFinder::MatchResult &Result) { 81 const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor"); 82 if (Ctor) 83 checkSeed(Result, Ctor); 84 85 const auto *Func = Result.Nodes.getNodeAs<CXXMemberCallExpr>("seed"); 86 if (Func) 87 checkSeed(Result, Func); 88 89 const auto *Srand = Result.Nodes.getNodeAs<CallExpr>("srand"); 90 if (Srand) 91 checkSeed(Result, Srand); 92 } 93 94 template <class T> 95 void ProperlySeededRandomGeneratorCheck::checkSeed( 96 const MatchFinder::MatchResult &Result, const T *Func) { 97 if (Func->getNumArgs() == 0 || Func->getArg(0)->isDefaultArgument()) { 98 diag(Func->getExprLoc(), 99 "random number generator seeded with a default argument will generate " 100 "a predictable sequence of values"); 101 return; 102 } 103 104 Expr::EvalResult EVResult; 105 if (Func->getArg(0)->EvaluateAsInt(EVResult, *Result.Context)) { 106 diag(Func->getExprLoc(), 107 "random number generator seeded with a constant value will generate a " 108 "predictable sequence of values"); 109 return; 110 } 111 112 const std::string SeedType( 113 Func->getArg(0)->IgnoreCasts()->getType().getAsString()); 114 if (llvm::find(DisallowedSeedTypes, SeedType) != DisallowedSeedTypes.end()) { 115 diag(Func->getExprLoc(), 116 "random number generator seeded with a disallowed source of seed " 117 "value will generate a predictable sequence of values"); 118 return; 119 } 120 } 121 122 } // namespace cert 123 } // namespace tidy 124 } // namespace clang 125