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