================ @@ -0,0 +1,264 @@ +//===----------------------------------------------------------------------===// +// +// 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 "UnsafeFormatStringCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/Support/ConvertUTF.h" +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions = + "CustomPrintfFunctions"; +static constexpr llvm::StringLiteral OptionNameCustomScanfFunctions = + "CustomScanfFunctions"; + +static constexpr llvm::StringLiteral BuiltInFormatBind = "format"; +static constexpr llvm::StringLiteral BuiltInCallBind = "call"; +static constexpr llvm::StringLiteral PrintfCallBind = "printfcall"; +static constexpr llvm::StringLiteral ScanfCallBind = "scanfcall"; + +static std::vector<UnsafeFormatStringCheck::CheckedFunction> +parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) { + const std::vector<StringRef> Functions = + utils::options::parseStringList(Option); + std::vector<UnsafeFormatStringCheck::CheckedFunction> Result; + Result.reserve(Functions.size()); + + for (const StringRef Function : Functions) { + if (Function.empty()) + continue; + const auto [Name, ParamCount] = Function.split(','); + unsigned long Count = 0; + if (Name.trim().empty() || ParamCount.trim().empty() || + ParamCount.trim().getAsInteger(10, Count)) { + Context->configurationDiag( + "invalid configuration value for option '%0'; " + "expected <functionname>, <paramcount>; pairs.") + << OptionNameCustomPrintfFunctions; + continue; + } + Result.push_back( + {Name.trim().str(), + matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()), + Count}); + } + + return Result; +} + +UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + CustomPrintfFunctions(parseCheckedFunctions( + Options.get(OptionNameCustomPrintfFunctions, ""), Context)), + CustomScanfFunctions(parseCheckedFunctions( + Options.get(OptionNameCustomScanfFunctions, ""), Context)) {} + +void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) { + // Matches sprintf and scanf family functions in std namespace in C++ and + // globally in C. + auto VulnerableFunctions = + hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf", + "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf", + "vwscanf", "vfwscanf", "vswscanf"); + Finder->addMatcher( + callExpr( + callee(functionDecl(VulnerableFunctions, + anyOf(isInStdNamespace(), + hasDeclContext(translationUnitDecl())))), + anyOf(hasArgument(0, stringLiteral().bind(BuiltInFormatBind)), + hasArgument(1, stringLiteral().bind(BuiltInFormatBind)))) + .bind(BuiltInCallBind), + this); + + if (!CustomPrintfFunctions.empty()) { + std::vector<llvm::StringRef> FunctionNames; + FunctionNames.reserve(CustomPrintfFunctions.size()); + + for (const auto &Entry : CustomPrintfFunctions) + FunctionNames.emplace_back(Entry.Name); + + auto CustomFunctionsMatcher = matchers::matchesAnyListedName(FunctionNames); + + Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher)))) + .bind(PrintfCallBind), + this); + } + + if (!CustomScanfFunctions.empty()) { + std::vector<llvm::StringRef> FunctionNames; + FunctionNames.reserve(CustomScanfFunctions.size()); + + for (const auto &Entry : CustomScanfFunctions) + FunctionNames.emplace_back(Entry.Name); + + auto CustomFunctionsMatcher = matchers::matchesAnyListedName(FunctionNames); + + Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher)))) + .bind(ScanfCallBind), + this); + } +} + +void UnsafeFormatStringCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, OptionNameCustomPrintfFunctions, ""); + Options.store(Opts, OptionNameCustomScanfFunctions, ""); +} + +const StringLiteral *UnsafeFormatStringCheck::getFormatLiteral( + const CallExpr *Call, const std::vector<CheckedFunction> &CustomFunctions) { + auto *FD = cast<FunctionDecl>(Call->getDirectCallee()); ---------------- EugeneZelenko wrote:
`const`? https://github.com/llvm/llvm-project/pull/168691 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
