Repository: llvm/llvm-project
File: clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp (C++)

Code before:
  StringRef ConfigFile =
      Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option);
  std::optional<TaintConfiguration> Config =
      getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile);
  if (!Config) {
    // We don't have external taint config, no parsing required.
    DynamicTaintRules = RuleLookupTy{};
    return;
  }

  GenericTaintRuleParser::RulesContTy Rules{
      ConfigParser.parseConfiguration(Option, std::move(*Config))};

  DynamicTaintRules.emplace(std::make_move_iterator(Rules.begin()),
                            std::make_move_iterator(Rules.end()));
}

bool isPointerToCharArray(const QualType &QT) {
  if (!QT->isPointerType())
    return false;
  QualType PointeeType = QT->getPointeeType();
  if (!PointeeType->isPointerType() ||
      !PointeeType->getPointeeType()->isCharType())
    return false;
  return true;
}

// The incoming parameters of the main function get tainted
// if the program called in an untrusted environment.
void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
  if (!C.inTopFrame() || C.getAnalysisManager()
                             .getAnalyzerOptions()
                             .ShouldAssumeControlledEnvironment)
    return;

  const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
  if (!FD || !FD->isMain() || FD->param_size() < 2)
    return;

  if (!FD->parameters()[0]->getType()->isIntegerType())
    return;

  if (!isPointerToCharArray(FD->parameters()[1]->getType()))
    return;
  ProgramStateRef State = C.getState();

  const MemRegion *ArgcReg =
      State->getRegion(FD->parameters()[0], C.getLocationContext());
  SVal ArgcSVal = State->getSVal(ArgcReg);
  State = addTaint(State, ArgcSVal);
  StringRef ArgcName = FD->parameters()[0]->getName();

Review comment (suggestion):
The type of `argv` and `envp` can be declared as either `char *argv[]` or `char **argv`. These are semantically equivalent (in this context the array notation decays to a pointer), but ensure that they are both recognized by the checker.

Code after:
  const GenericTaintRuleParser ConfigParser{*Mgr};
  std::string Option{"Config"};
  StringRef ConfigFile =
      Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option);
  std::optional<TaintConfiguration> Config =
      getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile);
  if (!Config) {
    // We don't have external taint config, no parsing required.
    DynamicTaintRules = RuleLookupTy{};
    return;
  }

  GenericTaintRuleParser::RulesContTy Rules{
      ConfigParser.parseConfiguration(Option, std::move(*Config))};

  DynamicTaintRules.emplace(std::make_move_iterator(Rules.begin()),
                            std::make_move_iterator(Rules.end()));
}

bool isPointerToCharArray(const QualType &QT) {
  if (!QT->isPointerType())
    return false;
  QualType PointeeType = QT->getPointeeType();
  return PointeeType->isPointerType() &&
         PointeeType->getPointeeType()->isCharType();
}

// The incoming parameters of the main function get tainted
// if the program called in an untrusted environment.
void GenericTaintChecker::checkBeginFunction(CheckerContext &C) const {
  if (!C.inTopFrame() || C.getAnalysisManager()
                             .getAnalyzerOptions()
                             .ShouldAssumeControlledEnvironment)
    return;

  const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
  if (!FD || !FD->isMain() || FD->param_size() < 2)
    return;

  if (!FD->parameters()[0]->getType()->isIntegerType())
    return;

  if (!isPointerToCharArray(FD->parameters()[1]->getType()))
    return;
  ProgramStateRef State = C.getState();

  const MemRegion *ArgcReg =
      State->getRegion(FD->parameters()[0], C.getLocationContext());
  SVal ArgcSVal = State->getSVal(ArgcReg);
  State = addTaint(State, ArgcSVal);
  StringRef ArgcName = FD->parameters()[0]->getName();