Commit 5b3983ba authored by Balázs Kéri's avatar Balázs Kéri
Browse files

[analyzer]StreamChecker refactoring (NFC).

Reviewers: Szelethus

Reviewed By: Szelethus

Subscribers: xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, donat.nagy, Charusso, dkrupp, Szelethus, gamesh411, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D73359
parent 034c2c67
Loading
Loading
Loading
Loading
+42 −39
Original line number Diff line number Diff line
@@ -94,15 +94,15 @@ private:
  void evalFreopen(const CallEvent &Call, CheckerContext &C) const;
  void evalFclose(const CallEvent &Call, CheckerContext &C) const;
  void evalFseek(const CallEvent &Call, CheckerContext &C) const;

  void checkArgNullStream(const CallEvent &Call, CheckerContext &C,
                          unsigned ArgI) const;
  bool checkNullStream(SVal SV, CheckerContext &C,
                       ProgramStateRef &State) const;
  void checkFseekWhence(SVal SV, CheckerContext &C,
                        ProgramStateRef &State) const;
  bool checkDoubleClose(const CallEvent &Call, CheckerContext &C,
                        ProgramStateRef &State) const;

  ProgramStateRef checkNullStream(SVal SV, CheckerContext &C,
                                  ProgramStateRef State) const;
  ProgramStateRef checkFseekWhence(SVal SV, CheckerContext &C,
                                   ProgramStateRef State) const;
  ProgramStateRef checkDoubleClose(const CallEvent &Call, CheckerContext &C,
                                   ProgramStateRef State) const;
};

} // end anonymous namespace
@@ -176,9 +176,8 @@ void StreamChecker::evalFreopen(const CallEvent &Call,
    return;
  // Do not allow NULL as passed stream pointer.
  // This is not specified in the man page but may crash on some system.
  checkNullStream(*StreamVal, C, State);
  // Check if error was generated.
  if (C.isDifferent())
  State = checkNullStream(*StreamVal, C, State);
  if (!State)
    return;

  SymbolRef StreamSym = StreamVal->getAsSymbol();
@@ -208,7 +207,8 @@ void StreamChecker::evalFreopen(const CallEvent &Call,

void StreamChecker::evalFclose(const CallEvent &Call, CheckerContext &C) const {
  ProgramStateRef State = C.getState();
  if (checkDoubleClose(Call, C, State))
  State = checkDoubleClose(Call, C, State);
  if (State)
    C.addTransition(State);
}

@@ -219,30 +219,31 @@ void StreamChecker::evalFseek(const CallEvent &Call, CheckerContext &C) const {

  ProgramStateRef State = C.getState();

  bool StateChanged = checkNullStream(Call.getArgSVal(0), C, State);
  // Check if error was generated.
  if (C.isDifferent())
  State = checkNullStream(Call.getArgSVal(0), C, State);
  if (!State)
    return;

  // Check the legality of the 'whence' argument of 'fseek'.
  State =
      checkFseekWhence(State->getSVal(AE2, C.getLocationContext()), C, State);
  if (!State)
    return;

  if (!C.isDifferent() && StateChanged)
  C.addTransition(State);
}

void StreamChecker::checkArgNullStream(const CallEvent &Call, CheckerContext &C,
                                       unsigned ArgI) const {
  ProgramStateRef State = C.getState();
  if (checkNullStream(Call.getArgSVal(ArgI), C, State))
  State = checkNullStream(Call.getArgSVal(ArgI), C, State);
  if (State)
    C.addTransition(State);
}

bool StreamChecker::checkNullStream(SVal SV, CheckerContext &C,
                                    ProgramStateRef &State) const {
ProgramStateRef StreamChecker::checkNullStream(SVal SV, CheckerContext &C,
                                               ProgramStateRef State) const {
  Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
  if (!DV)
    return false;
    return State;

  ConstraintManager &CM = C.getConstraintManager();
  ProgramStateRef StateNotNull, StateNull;
@@ -256,26 +257,22 @@ bool StreamChecker::checkNullStream(SVal SV, CheckerContext &C,
      C.emitReport(std::make_unique<PathSensitiveBugReport>(
          *BT_nullfp, BT_nullfp->getDescription(), N));
    }
    return false;
    return nullptr;
  }

  if (StateNotNull) {
    State = StateNotNull;
    return true;
  }

  return false;
  return StateNotNull;
}

void StreamChecker::checkFseekWhence(SVal SV, CheckerContext &C,
                                     ProgramStateRef &State) const {
// Check the legality of the 'whence' argument of 'fseek'.
ProgramStateRef StreamChecker::checkFseekWhence(SVal SV, CheckerContext &C,
                                                ProgramStateRef State) const {
  Optional<nonloc::ConcreteInt> CI = SV.getAs<nonloc::ConcreteInt>();
  if (!CI)
    return;
    return State;

  int64_t X = CI->getValue().getSExtValue();
  if (X >= 0 && X <= 2)
    return;
    return State;

  if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
    if (!BT_illegalwhence)
@@ -285,20 +282,24 @@ void StreamChecker::checkFseekWhence(SVal SV, CheckerContext &C,
                         "SEEK_SET, SEEK_END, or SEEK_CUR."));
    C.emitReport(std::make_unique<PathSensitiveBugReport>(
        *BT_illegalwhence, BT_illegalwhence->getDescription(), N));
    return nullptr;
  }

  return State;
}

bool StreamChecker::checkDoubleClose(const CallEvent &Call, CheckerContext &C,
                                     ProgramStateRef &State) const {
ProgramStateRef StreamChecker::checkDoubleClose(const CallEvent &Call,
                                                CheckerContext &C,
                                                ProgramStateRef State) const {
  SymbolRef Sym = Call.getArgSVal(0).getAsSymbol();
  if (!Sym)
    return false;
    return State;

  const StreamState *SS = State->get<StreamMap>(Sym);

  // If the file stream is not tracked, return.
  if (!SS)
    return false;
    return State;

  // Check: Double close a File Descriptor could cause undefined behaviour.
  // Conforming to man-pages
@@ -311,14 +312,16 @@ bool StreamChecker::checkDoubleClose(const CallEvent &Call, CheckerContext &C,
                                   " closed. Cause undefined behaviour."));
      C.emitReport(std::make_unique<PathSensitiveBugReport>(
          *BT_doubleclose, BT_doubleclose->getDescription(), N));
      return nullptr;
    }
    return false;

    return State;
  }

  // Close the File Descriptor.
  State = State->set<StreamMap>(Sym, StreamState::getClosed());

  return true;
  return State;
}

void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper,