| //===--- ProperlySeededRandomGeneratorCheck.cpp - clang-tidy---------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "ProperlySeededRandomGeneratorCheck.h" | 
 | #include "clang/AST/ASTContext.h" | 
 | #include "clang/ASTMatchers/ASTMatchFinder.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 |  | 
 | using namespace clang::ast_matchers; | 
 |  | 
 | namespace clang { | 
 | namespace tidy { | 
 | namespace cert { | 
 |  | 
 | ProperlySeededRandomGeneratorCheck::ProperlySeededRandomGeneratorCheck( | 
 |     StringRef Name, ClangTidyContext *Context) | 
 |     : ClangTidyCheck(Name, Context), | 
 |       RawDisallowedSeedTypes( | 
 |           Options.get("DisallowedSeedTypes", "time_t,std::time_t")) { | 
 |   StringRef(RawDisallowedSeedTypes).split(DisallowedSeedTypes, ','); | 
 | } | 
 |  | 
 | void ProperlySeededRandomGeneratorCheck::storeOptions( | 
 |     ClangTidyOptions::OptionMap &Opts) { | 
 |   Options.store(Opts, "DisallowedSeedTypes", RawDisallowedSeedTypes); | 
 | } | 
 |  | 
 | void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) { | 
 |   auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName( | 
 |       "::std::linear_congruential_engine", "::std::mersenne_twister_engine", | 
 |       "::std::subtract_with_carry_engine", "::std::discard_block_engine", | 
 |       "::std::independent_bits_engine", "::std::shuffle_order_engine")); | 
 |   auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType( | 
 |       recordType(hasDeclaration(RandomGeneratorEngineDecl)))); | 
 |  | 
 |   // std::mt19937 engine; | 
 |   // engine.seed(); | 
 |   //        ^ | 
 |   // engine.seed(1); | 
 |   //        ^ | 
 |   // const int x = 1; | 
 |   // engine.seed(x); | 
 |   //        ^ | 
 |   Finder->addMatcher( | 
 |       cxxMemberCallExpr( | 
 |           has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)), | 
 |                          member(hasName("seed")), | 
 |                          unless(hasDescendant(cxxThisExpr()))))) | 
 |           .bind("seed"), | 
 |       this); | 
 |  | 
 |   // std::mt19937 engine; | 
 |   //              ^ | 
 |   // std::mt19937 engine(1); | 
 |   //              ^ | 
 |   // const int x = 1; | 
 |   // std::mt19937 engine(x); | 
 |   //              ^ | 
 |   Finder->addMatcher( | 
 |       traverse(ast_type_traits::TK_AsIs, | 
 |                cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor")), | 
 |       this); | 
 |  | 
 |   // srand(); | 
 |   // ^ | 
 |   // const int x = 1; | 
 |   // srand(x); | 
 |   // ^ | 
 |   Finder->addMatcher( | 
 |       callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand")))) | 
 |           .bind("srand"), | 
 |       this); | 
 | } | 
 |  | 
 | void ProperlySeededRandomGeneratorCheck::check( | 
 |     const MatchFinder::MatchResult &Result) { | 
 |   const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor"); | 
 |   if (Ctor) | 
 |     checkSeed(Result, Ctor); | 
 |  | 
 |   const auto *Func = Result.Nodes.getNodeAs<CXXMemberCallExpr>("seed"); | 
 |   if (Func) | 
 |     checkSeed(Result, Func); | 
 |  | 
 |   const auto *Srand = Result.Nodes.getNodeAs<CallExpr>("srand"); | 
 |   if (Srand) | 
 |     checkSeed(Result, Srand); | 
 | } | 
 |  | 
 | template <class T> | 
 | void ProperlySeededRandomGeneratorCheck::checkSeed( | 
 |     const MatchFinder::MatchResult &Result, const T *Func) { | 
 |   if (Func->getNumArgs() == 0 || Func->getArg(0)->isDefaultArgument()) { | 
 |     diag(Func->getExprLoc(), | 
 |          "random number generator seeded with a default argument will generate " | 
 |          "a predictable sequence of values"); | 
 |     return; | 
 |   } | 
 |  | 
 |   Expr::EvalResult EVResult; | 
 |   if (Func->getArg(0)->EvaluateAsInt(EVResult, *Result.Context)) { | 
 |     diag(Func->getExprLoc(), | 
 |          "random number generator seeded with a constant value will generate a " | 
 |          "predictable sequence of values"); | 
 |     return; | 
 |   } | 
 |  | 
 |   const std::string SeedType( | 
 |       Func->getArg(0)->IgnoreCasts()->getType().getAsString()); | 
 |   if (llvm::find(DisallowedSeedTypes, SeedType) != DisallowedSeedTypes.end()) { | 
 |     diag(Func->getExprLoc(), | 
 |          "random number generator seeded with a disallowed source of seed " | 
 |          "value will generate a predictable sequence of values"); | 
 |     return; | 
 |   } | 
 | } | 
 |  | 
 | } // namespace cert | 
 | } // namespace tidy | 
 | } // namespace clang |