diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp')
| -rw-r--r-- | clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp new file mode 100644 index 0000000..3e32e9b --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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 "RandomGeneratorSeedCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/STLExtras.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +RandomGeneratorSeedCheck::RandomGeneratorSeedCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + RawDisallowedSeedTypes( + Options.get("DisallowedSeedTypes", "time_t,std::time_t")) { + RawDisallowedSeedTypes.split(DisallowedSeedTypes, ','); +} + +void RandomGeneratorSeedCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "DisallowedSeedTypes", RawDisallowedSeedTypes); +} + +void RandomGeneratorSeedCheck::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 RandomGeneratorSeedCheck::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 RandomGeneratorSeedCheck::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::bugprone |
