15bee05c5SAaron Ballman //===--- ProperlySeededRandomGeneratorCheck.cpp - clang-tidy---------------===//
25bee05c5SAaron Ballman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65bee05c5SAaron Ballman //
75bee05c5SAaron Ballman //===----------------------------------------------------------------------===//
85bee05c5SAaron Ballman
95bee05c5SAaron Ballman #include "ProperlySeededRandomGeneratorCheck.h"
105bee05c5SAaron Ballman #include "clang/AST/ASTContext.h"
115bee05c5SAaron Ballman #include "clang/ASTMatchers/ASTMatchFinder.h"
125bee05c5SAaron Ballman #include "llvm/ADT/STLExtras.h"
135bee05c5SAaron Ballman
145bee05c5SAaron Ballman using namespace clang::ast_matchers;
155bee05c5SAaron Ballman
16*7d2ea6c4SCarlos Galvez namespace clang::tidy::cert {
175bee05c5SAaron Ballman
ProperlySeededRandomGeneratorCheck(StringRef Name,ClangTidyContext * Context)185bee05c5SAaron Ballman ProperlySeededRandomGeneratorCheck::ProperlySeededRandomGeneratorCheck(
195bee05c5SAaron Ballman StringRef Name, ClangTidyContext *Context)
205bee05c5SAaron Ballman : ClangTidyCheck(Name, Context),
215bee05c5SAaron Ballman RawDisallowedSeedTypes(
225bee05c5SAaron Ballman Options.get("DisallowedSeedTypes", "time_t,std::time_t")) {
235bee05c5SAaron Ballman StringRef(RawDisallowedSeedTypes).split(DisallowedSeedTypes, ',');
245bee05c5SAaron Ballman }
255bee05c5SAaron Ballman
storeOptions(ClangTidyOptions::OptionMap & Opts)265bee05c5SAaron Ballman void ProperlySeededRandomGeneratorCheck::storeOptions(
275bee05c5SAaron Ballman ClangTidyOptions::OptionMap &Opts) {
285bee05c5SAaron Ballman Options.store(Opts, "DisallowedSeedTypes", RawDisallowedSeedTypes);
295bee05c5SAaron Ballman }
305bee05c5SAaron Ballman
registerMatchers(MatchFinder * Finder)315bee05c5SAaron Ballman void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) {
325bee05c5SAaron Ballman auto RandomGeneratorEngineDecl = cxxRecordDecl(hasAnyName(
335bee05c5SAaron Ballman "::std::linear_congruential_engine", "::std::mersenne_twister_engine",
345bee05c5SAaron Ballman "::std::subtract_with_carry_engine", "::std::discard_block_engine",
355bee05c5SAaron Ballman "::std::independent_bits_engine", "::std::shuffle_order_engine"));
365bee05c5SAaron Ballman auto RandomGeneratorEngineTypeMatcher = hasType(hasUnqualifiedDesugaredType(
375bee05c5SAaron Ballman recordType(hasDeclaration(RandomGeneratorEngineDecl))));
385bee05c5SAaron Ballman
395bee05c5SAaron Ballman // std::mt19937 engine;
405bee05c5SAaron Ballman // engine.seed();
415bee05c5SAaron Ballman // ^
425bee05c5SAaron Ballman // engine.seed(1);
435bee05c5SAaron Ballman // ^
445bee05c5SAaron Ballman // const int x = 1;
455bee05c5SAaron Ballman // engine.seed(x);
465bee05c5SAaron Ballman // ^
475bee05c5SAaron Ballman Finder->addMatcher(
485bee05c5SAaron Ballman cxxMemberCallExpr(
495bee05c5SAaron Ballman has(memberExpr(has(declRefExpr(RandomGeneratorEngineTypeMatcher)),
505bee05c5SAaron Ballman member(hasName("seed")),
515bee05c5SAaron Ballman unless(hasDescendant(cxxThisExpr())))))
525bee05c5SAaron Ballman .bind("seed"),
535bee05c5SAaron Ballman this);
545bee05c5SAaron Ballman
555bee05c5SAaron Ballman // std::mt19937 engine;
565bee05c5SAaron Ballman // ^
575bee05c5SAaron Ballman // std::mt19937 engine(1);
585bee05c5SAaron Ballman // ^
595bee05c5SAaron Ballman // const int x = 1;
605bee05c5SAaron Ballman // std::mt19937 engine(x);
615bee05c5SAaron Ballman // ^
625bee05c5SAaron Ballman Finder->addMatcher(
63027899daSAlexander Kornienko traverse(TK_AsIs,
64a72307c3SStephen Kelly cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor")),
65a72307c3SStephen Kelly this);
665bee05c5SAaron Ballman
675bee05c5SAaron Ballman // srand();
685bee05c5SAaron Ballman // ^
695bee05c5SAaron Ballman // const int x = 1;
705bee05c5SAaron Ballman // srand(x);
715bee05c5SAaron Ballman // ^
725bee05c5SAaron Ballman Finder->addMatcher(
735bee05c5SAaron Ballman callExpr(callee(functionDecl(hasAnyName("::srand", "::std::srand"))))
745bee05c5SAaron Ballman .bind("srand"),
755bee05c5SAaron Ballman this);
765bee05c5SAaron Ballman }
775bee05c5SAaron Ballman
check(const MatchFinder::MatchResult & Result)785bee05c5SAaron Ballman void ProperlySeededRandomGeneratorCheck::check(
795bee05c5SAaron Ballman const MatchFinder::MatchResult &Result) {
805bee05c5SAaron Ballman const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructExpr>("ctor");
815bee05c5SAaron Ballman if (Ctor)
825bee05c5SAaron Ballman checkSeed(Result, Ctor);
835bee05c5SAaron Ballman
845bee05c5SAaron Ballman const auto *Func = Result.Nodes.getNodeAs<CXXMemberCallExpr>("seed");
855bee05c5SAaron Ballman if (Func)
865bee05c5SAaron Ballman checkSeed(Result, Func);
875bee05c5SAaron Ballman
885bee05c5SAaron Ballman const auto *Srand = Result.Nodes.getNodeAs<CallExpr>("srand");
895bee05c5SAaron Ballman if (Srand)
905bee05c5SAaron Ballman checkSeed(Result, Srand);
915bee05c5SAaron Ballman }
925bee05c5SAaron Ballman
935bee05c5SAaron Ballman template <class T>
checkSeed(const MatchFinder::MatchResult & Result,const T * Func)945bee05c5SAaron Ballman void ProperlySeededRandomGeneratorCheck::checkSeed(
955bee05c5SAaron Ballman const MatchFinder::MatchResult &Result, const T *Func) {
965bee05c5SAaron Ballman if (Func->getNumArgs() == 0 || Func->getArg(0)->isDefaultArgument()) {
975bee05c5SAaron Ballman diag(Func->getExprLoc(),
985bee05c5SAaron Ballman "random number generator seeded with a default argument will generate "
995bee05c5SAaron Ballman "a predictable sequence of values");
1005bee05c5SAaron Ballman return;
1015bee05c5SAaron Ballman }
1025bee05c5SAaron Ballman
103cab8dd69SHans Wennborg Expr::EvalResult EVResult;
104cab8dd69SHans Wennborg if (Func->getArg(0)->EvaluateAsInt(EVResult, *Result.Context)) {
1055bee05c5SAaron Ballman diag(Func->getExprLoc(),
1065bee05c5SAaron Ballman "random number generator seeded with a constant value will generate a "
1075bee05c5SAaron Ballman "predictable sequence of values");
1085bee05c5SAaron Ballman return;
1095bee05c5SAaron Ballman }
1105bee05c5SAaron Ballman
1115bee05c5SAaron Ballman const std::string SeedType(
1125bee05c5SAaron Ballman Func->getArg(0)->IgnoreCasts()->getType().getAsString());
1137542e721SKazu Hirata if (llvm::is_contained(DisallowedSeedTypes, SeedType)) {
1145bee05c5SAaron Ballman diag(Func->getExprLoc(),
1155bee05c5SAaron Ballman "random number generator seeded with a disallowed source of seed "
1165bee05c5SAaron Ballman "value will generate a predictable sequence of values");
1175bee05c5SAaron Ballman return;
1185bee05c5SAaron Ballman }
1195bee05c5SAaron Ballman }
1205bee05c5SAaron Ballman
121*7d2ea6c4SCarlos Galvez } // namespace clang::tidy::cert
122