aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp')
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/RandomGeneratorSeedCheck.cpp119
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