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

Code before:
// 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;

  ProgramStateRef State = C.getState();
  const MemRegion *ArgvReg =
      State->getRegion(FD->parameters()[1], C.getLocationContext());
  SVal ArgvSval = State->getSVal(ArgvReg);
  // Add taintedness to argv**
  State = addTaint(State, ArgvSval);

  const NoteTag *OriginatingTag =
      C.getNoteTag([ArgvSval](PathSensitiveBugReport &BR) -> std::string {
        // We give diagnostics only for taint related reports
        if (!BR.isInteresting(ArgvSval) ||
            BR.getBugType().getCategory() != categories::TaintedData)
          return "";

        return MsgTaintOrigin;
      });
  C.addTransition(State, OriginatingTag);
}

void GenericTaintChecker::checkPreCall(const CallEvent &Call,
                                       CheckerContext &C) const {

  initTaintRules(C);

  // FIXME: this should be much simpler.
  if (const auto *Rule =
          Call.isGlobalCFunction() ? StaticTaintRules->lookup(Call) : nullptr)
    Rule->process(*this, Call, C);
  else if (const auto *Rule = DynamicTaintRules->lookup(Call))
    Rule->process(*this, Call, C);

  // FIXME: These edge cases are to be eliminated from here eventually.
  //
  // Additional check that is not supported by CallDescription.
  // TODO: Make CallDescription be able to match attributes such as printf-like
  // arguments.
  checkUncontrolledFormatString(Call, C);

  // TODO: Modeling sockets should be done in a specific checker.
  // Socket is a source, which taints the return value.

Review comment (suggestion):
Instead of using the generic canned message, consider using "Taint originated in the parameter 'argv'" (with code that inserts the actual name of the argument).

The current behavior is acceptable, but this would be more user-friendly. Also in `main` there is only one relevant taint source, but if you later want to generalize this behavior for other functions (that are marked as "interface/entry" functions by the user), then naming the argument will be important to clarify the situation.

Code after:
  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();
  if (auto N = ArgcSVal.getAs<NonLoc>()) {
    ConstraintManager &CM = C.getConstraintManager();
    // The upper bound is the ARG_MAX on an arbitrary Linux
    // to model that is is typically smaller than INT_MAX.
    State = CM.assumeInclusiveRange(State, *N, llvm::APSInt::getUnsigned(1),
                                    llvm::APSInt::getUnsigned(2097152), true);
  }

  const MemRegion *ArgvReg =
      State->getRegion(FD->parameters()[1], C.getLocationContext());
  SVal ArgvSVal = State->getSVal(ArgvReg);
  State = addTaint(State, ArgvSVal);
  StringRef ArgvName = FD->parameters()[1]->getName();

  bool HaveEnvp = FD->param_size() > 2;
  SVal EnvpSVal;
  StringRef EnvpName;
  if (HaveEnvp && !isPointerToCharArray(FD->parameters()[2]->getType()))
    return;
  if (HaveEnvp) {