|  | //===--- 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::tidy::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(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::is_contained(DisallowedSeedTypes, SeedType)) { | 
|  | diag(Func->getExprLoc(), | 
|  | "random number generator seeded with a disallowed source of seed " | 
|  | "value will generate a predictable sequence of values"); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | } // namespace clang::tidy::cert |