balazske updated this revision to Diff 222138.
balazske added a comment.

Using CallDescriptionMap.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67706/new/

https://reviews.llvm.org/D67706

Files:
  clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp

Index: clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -57,38 +57,53 @@
 
 class StreamChecker : public Checker<eval::Call,
                                      check::DeadSymbols > {
-  CallDescription CD_fopen, CD_tmpfile, CD_fclose, CD_fread, CD_fwrite,
-      CD_fseek, CD_ftell, CD_rewind, CD_fgetpos, CD_fsetpos, CD_clearerr,
-      CD_feof, CD_ferror, CD_fileno;
   mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
       BT_doubleclose, BT_ResourceLeak;
 
 public:
-  StreamChecker()
-      : CD_fopen("fopen"), CD_tmpfile("tmpfile"), CD_fclose("fclose", 1),
-        CD_fread("fread", 4), CD_fwrite("fwrite", 4), CD_fseek("fseek", 3),
-        CD_ftell("ftell", 1), CD_rewind("rewind", 1), CD_fgetpos("fgetpos", 2),
-        CD_fsetpos("fsetpos", 2), CD_clearerr("clearerr", 1),
-        CD_feof("feof", 1), CD_ferror("ferror", 1), CD_fileno("fileno", 1) {}
+  StreamChecker() = default;
 
   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
 
 private:
-  void Fopen(CheckerContext &C, const CallExpr *CE) const;
-  void Tmpfile(CheckerContext &C, const CallExpr *CE) const;
-  void Fclose(CheckerContext &C, const CallExpr *CE) const;
-  void Fread(CheckerContext &C, const CallExpr *CE) const;
-  void Fwrite(CheckerContext &C, const CallExpr *CE) const;
-  void Fseek(CheckerContext &C, const CallExpr *CE) const;
-  void Ftell(CheckerContext &C, const CallExpr *CE) const;
-  void Rewind(CheckerContext &C, const CallExpr *CE) const;
-  void Fgetpos(CheckerContext &C, const CallExpr *CE) const;
-  void Fsetpos(CheckerContext &C, const CallExpr *CE) const;
-  void Clearerr(CheckerContext &C, const CallExpr *CE) const;
-  void Feof(CheckerContext &C, const CallExpr *CE) const;
-  void Ferror(CheckerContext &C, const CallExpr *CE) const;
-  void Fileno(CheckerContext &C, const CallExpr *CE) const;
+  typedef void (StreamChecker::*FnCheck)(CheckerContext &,
+                                         const CallExpr *) const;
+
+  CallDescriptionMap<FnCheck> Callbacks = {
+      {{CDF_MaybeBuiltin, "fopen"}, &StreamChecker::evalFopen},
+      {{CDF_MaybeBuiltin, "tmpfile"}, &StreamChecker::evalTmpfile},
+      {{CDF_MaybeBuiltin, "fclose", 1}, &StreamChecker::evalFclose},
+      {{CDF_MaybeBuiltin, "fread", 4}, &StreamChecker::evalFread},
+      {{CDF_MaybeBuiltin, "fwrite", 4}, &StreamChecker::evalFwrite},
+      {{CDF_MaybeBuiltin, "fseek", 3}, &StreamChecker::evalFseek},
+      {{CDF_MaybeBuiltin, "ftell", 1}, &StreamChecker::evalFtell},
+      {{CDF_MaybeBuiltin, "rewind", 1}, &StreamChecker::evalRewind},
+      {{CDF_MaybeBuiltin, "fgetpos", 2}, &StreamChecker::evalFgetpos},
+      {{CDF_MaybeBuiltin, "fsetpos", 2}, &StreamChecker::evalFsetpos},
+      {{CDF_MaybeBuiltin, "clearerr", 1}, &StreamChecker::evalClearerr},
+      {{CDF_MaybeBuiltin, "feof", 1}, &StreamChecker::evalFeof},
+      {{CDF_MaybeBuiltin, "ferror", 1}, &StreamChecker::evalFerror},
+      {{CDF_MaybeBuiltin, "fileno", 1}, &StreamChecker::evalFileno},
+  };
+
+  FnCheck identifyCall(const CallEvent &Call, CheckerContext &C,
+                       const CallExpr *CE) const;
+
+  void evalFopen(CheckerContext &C, const CallExpr *CE) const;
+  void evalTmpfile(CheckerContext &C, const CallExpr *CE) const;
+  void evalFclose(CheckerContext &C, const CallExpr *CE) const;
+  void evalFread(CheckerContext &C, const CallExpr *CE) const;
+  void evalFwrite(CheckerContext &C, const CallExpr *CE) const;
+  void evalFseek(CheckerContext &C, const CallExpr *CE) const;
+  void evalFtell(CheckerContext &C, const CallExpr *CE) const;
+  void evalRewind(CheckerContext &C, const CallExpr *CE) const;
+  void evalFgetpos(CheckerContext &C, const CallExpr *CE) const;
+  void evalFsetpos(CheckerContext &C, const CallExpr *CE) const;
+  void evalClearerr(CheckerContext &C, const CallExpr *CE) const;
+  void evalFeof(CheckerContext &C, const CallExpr *CE) const;
+  void evalFerror(CheckerContext &C, const CallExpr *CE) const;
+  void evalFileno(CheckerContext &C, const CallExpr *CE) const;
 
   void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
 
@@ -115,120 +130,58 @@
   if (!CE)
     return false;
 
-  if (Call.isCalled(CD_fopen)) {
-    Fopen(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_tmpfile)) {
-    Tmpfile(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fclose)) {
-    Fclose(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fread)) {
-    Fread(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fwrite)) {
-    Fwrite(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fseek)) {
-    Fseek(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_ftell)) {
-    Ftell(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_rewind)) {
-    Rewind(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fgetpos)) {
-    Fgetpos(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fsetpos)) {
-    Fsetpos(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_clearerr)) {
-    Clearerr(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_feof)) {
-    Feof(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_ferror)) {
-    Ferror(C, CE);
-    return true;
-  }
-  if (Call.isCalled(CD_fileno)) {
-    Fileno(C, CE);
-    return true;
-  }
+  FnCheck Callback = identifyCall(Call, C, CE);
+  if (!Callback)
+    return false;
 
-  return false;
-}
+  (this->*Callback)(C, CE);
 
-void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) const {
-  OpenFileAux(C, CE);
+  return true;
 }
 
-void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const {
-  OpenFileAux(C, CE);
-}
+StreamChecker::FnCheck StreamChecker::identifyCall(const CallEvent &Call,
+                                                   CheckerContext &C,
+                                                   const CallExpr *CE) const {
+  for (auto I : CE->arguments()) {
+    QualType T = I->getType();
+    if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
+      return nullptr;
+  }
 
-void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
-  ProgramStateRef state = C.getState();
-  SValBuilder &svalBuilder = C.getSValBuilder();
-  const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
-  DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
-                                                    C.blockCount())
-      .castAs<DefinedSVal>();
-  state = state->BindExpr(CE, C.getLocationContext(), RetVal);
+  const FnCheck *Callback = Callbacks.lookup(Call);
+  if (!Callback)
+    return nullptr;
 
-  ConstraintManager &CM = C.getConstraintManager();
-  // Bifurcate the state into two: one with a valid FILE* pointer, the other
-  // with a NULL.
-  ProgramStateRef stateNotNull, stateNull;
-  std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
+  return *Callback;
+}
 
-  if (SymbolRef Sym = RetVal.getAsSymbol()) {
-    // if RetVal is not NULL, set the symbol's state to Opened.
-    stateNotNull =
-      stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE));
-    stateNull =
-      stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
+void StreamChecker::evalFopen(CheckerContext &C, const CallExpr *CE) const {
+  OpenFileAux(C, CE);
+}
 
-    C.addTransition(stateNotNull);
-    C.addTransition(stateNull);
-  }
+void StreamChecker::evalTmpfile(CheckerContext &C, const CallExpr *CE) const {
+  OpenFileAux(C, CE);
 }
 
-void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFclose(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = CheckDoubleClose(CE, C.getState(), C);
   if (state)
     C.addTransition(state);
 }
 
-void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFread(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C))
     return;
 }
 
-void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFwrite(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C))
     return;
 }
 
-void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFseek(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!(state = CheckNullStream(C.getSVal(CE->getArg(0)), state, C)))
     return;
@@ -254,54 +207,80 @@
   }
 }
 
-void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFtell(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalRewind(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFgetpos(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFsetpos(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalClearerr(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFeof(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFerror(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
-void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const {
+void StreamChecker::evalFileno(CheckerContext &C, const CallExpr *CE) const {
   ProgramStateRef state = C.getState();
   if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C))
     return;
 }
 
+void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
+  ProgramStateRef state = C.getState();
+  SValBuilder &svalBuilder = C.getSValBuilder();
+  const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
+  DefinedSVal RetVal =
+      svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount())
+          .castAs<DefinedSVal>();
+  state = state->BindExpr(CE, C.getLocationContext(), RetVal);
+
+  ConstraintManager &CM = C.getConstraintManager();
+  // Bifurcate the state into two: one with a valid FILE* pointer, the other
+  // with a NULL.
+  ProgramStateRef stateNotNull, stateNull;
+  std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
+
+  if (SymbolRef Sym = RetVal.getAsSymbol()) {
+    // if RetVal is not NULL, set the symbol's state to Opened.
+    stateNotNull =
+        stateNotNull->set<StreamMap>(Sym, StreamState::getOpened(CE));
+    stateNull = stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE));
+
+    C.addTransition(stateNotNull);
+    C.addTransition(stateNull);
+  }
+}
+
 ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state,
                                     CheckerContext &C) const {
   Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>();
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to