//===--- 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("ctor"); if (Ctor) checkSeed(Result, Ctor); const auto *Func = Result.Nodes.getNodeAs("seed"); if (Func) checkSeed(Result, Func); const auto *Srand = Result.Nodes.getNodeAs("srand"); if (Srand) checkSeed(Result, Srand); } template 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