haowei updated this revision to Diff 107201.
haowei added a comment.

Thanks for reviewing this patch. I have modified the checker according NoQ's 
suggestions and refactored some long functions.

> We're trying to use this CallDescription thing for this purpose recently.

I took a look at CallDescption, but it can only be used when a CallEvent object 
is present, which is not available in evalCall callbacks. So we cannot use it 
in our checker. BTW, we have been working on a function matching based on 
annotation attributes to avoid string comparison as much as possible. But the 
patch is relatively huge so we would like to land this patch first before 
publishing the annotation attribute stuff.

> This should be fixed by allowing checkPointerEscape report non-pointer 
> escapes, or making a separate callback for non-pointer escapes. This huge 
> boilerplate shouldn't be repeated in every checker that needs it.

I agree. For example following code is not covered by the workaround I used in 
the checker:
struct A {

  mx_handle_t data,
  mx_status_t status,

};
escapeFunction(A arg1);

And it would be hard to implement a workaround in the checker to cover this 
case. I would like to help but I quite new to the Clang and Clang Static 
Analyzer. Currently I don't know where to start to fix this issue in the static 
analyzer. If you have any suggestions on how to fix it in the Clang, let me 
know.

> While this is the easiest thing to do, it halves the analyzer performance 
> every time it happens, exploding the complexity exponentially - because the 
> remaining path would be split up into two paths, which are analyzed 
> independently. So it is really really rarely a good idea to split the state 
> in the checker.

When I first worked on this checker, I actually use ProgramState to track 
return values of syscalls, which is very similar to the approach used by 
https://reviews.llvm.org/D32449. But after I read the implementation of 
StreamChecker, I noticed that it uses program state bifurcation which is more 
straightforward. So I changed my checker to use this feature as well.

After receiving your suggestion, I conducted a benchmark to compare the 
performance of my previous return value approach with current state bifurcation 
approach. It took 11m46.383s to analyze magenta kernel code base by tracking 
the return value of syscalls compare to 11m39.034s by using state bifurcation. 
So in my case, the state bifurcation is actually faster, though I am not quite 
sure about the reason.

Another reason that we would like to keep the state bifurcation approach is 
that for magenta handle acquire and release syscalls. Both handle acquire 
syscall and handle release syscall may fail, so the return value of both types 
of syscalls should be tracked and should be tracked separately. The 
PthreadLockChecker only tracked one. It would be a lot of harder to get things 
right if we use return value tracking approach when adding more syscalls 
support.

Let me know if you have further suggestions or concerns.

Thanks,
Haowei


https://reviews.llvm.org/D34724

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/MagentaHandleChecker.cpp
  test/Analysis/mxhandle.c

Index: test/Analysis/mxhandle.c
===================================================================
--- /dev/null
+++ test/Analysis/mxhandle.c
@@ -0,0 +1,217 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.magenta.MagentaHandleChecker -analyzer-store=region -verify %s
+
+typedef __typeof__(sizeof(int)) size_t;
+typedef int mx_status_t;
+typedef __typeof__(sizeof(int)) mx_handle_t;
+typedef unsigned int uint32_t;
+#define NULL ((void *)0)
+
+mx_status_t mx_channel_create(
+   uint32_t options,
+   mx_handle_t* out0,
+   mx_handle_t* out1);
+
+mx_status_t mx_handle_close(mx_handle_t handle);
+
+mx_status_t mx_channel_read(mx_handle_t handle, uint32_t options,
+                            void* bytes, mx_handle_t* handles,
+                            uint32_t num_bytes, uint32_t num_handles,
+                            uint32_t* actual_bytes, uint32_t* actual_handles);
+
+mx_status_t mx_channel_write(mx_handle_t handle, uint32_t options,
+                             void* bytes, uint32_t num_bytes,
+                             mx_handle_t* handles, uint32_t num_handles);
+
+void escapeMethod(mx_handle_t *in);
+void useHandle(mx_handle_t handle);
+
+// End of declaration
+
+void checkNoLeak01() {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  mx_handle_close(sa);
+  mx_handle_close(sb);
+}
+
+void checkNoLeak02() {
+  mx_handle_t ay[2];
+  mx_channel_create(0, &ay[0], &ay[1]);
+  mx_handle_close(ay[0]);
+  mx_handle_close(ay[1]);
+}
+
+void checkNoLeak03() {
+  mx_handle_t ay[2];
+  mx_channel_create(0, &ay[0], &ay[1]);
+  for (int i = 0; i < 2; i++) {
+    mx_handle_close(ay[i]);
+  }
+}
+
+mx_handle_t checkNoLeak04() {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  mx_handle_close(sa);
+  return sb; // no warning
+}
+
+mx_handle_t checkNoLeak05(mx_handle_t *out1) {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  *out1 = sa;
+  return sb; // no warning
+}
+
+void checkNoLeak06(mx_handle_t handle) {
+  mx_handle_t handlebuf[4];
+  uint32_t hcount;
+  mx_channel_read(handle, 0, NULL, handlebuf, 0, 4, 0, &hcount);
+  for (int i = 0; i < hcount; i++) {
+    mx_handle_close(handlebuf[i]);
+  }
+}
+
+void checkNoLeak07(mx_handle_t handle, uint32_t hcount) {
+  mx_handle_t handlebuf[6];
+  mx_channel_read(handle, 0, NULL, handlebuf, 0, hcount, 0, &hcount);
+  for (int i = 0; i < hcount; i++) {
+    mx_handle_close(handlebuf[i]);
+  }
+}
+
+void checkNoLeak08(mx_handle_t handle) {
+  mx_handle_t handlebuf[4];
+  uint32_t hcount;
+  mx_channel_read(handle, 0, NULL, handlebuf, 0, 4, 0, &hcount);
+  if (mx_channel_write(handle, 0, NULL, 0, handlebuf, hcount) < 0) {
+    for (int i = 0; i < hcount; i++) {
+      mx_handle_close(handlebuf[i]);
+    }
+  }
+}
+
+void checkNoLeak09(mx_handle_t handle, uint32_t hcount) {
+  mx_handle_t handlebuf[6];
+  mx_channel_read(handle, 0, NULL, handlebuf, 0, hcount, 0, &hcount);
+  if (mx_channel_write(handle, 0, NULL, 0, handlebuf, hcount) < 0) {
+    for (int i = 0; i < hcount; i++) {
+      mx_handle_close(handlebuf[i]);
+    }
+  }
+}
+
+void checkNoLeak10() {
+  mx_handle_t sa, sb;
+  if (mx_channel_create(0, &sa, &sb) < 0) {
+    return;
+  }
+  mx_handle_close(sa);
+  mx_handle_close(sb);
+}
+
+void checkNoLeak11(mx_handle_t handle, uint32_t hcount) {
+  mx_handle_t handlebuf[6];
+  mx_status_t r = mx_channel_read(handle, 0, NULL,
+                                  handlebuf, 0, hcount, 0, &hcount);
+  if (r < 0) {
+    return;
+  }
+  for (int i = 0; i < hcount; i++) {
+    mx_handle_close(handlebuf[i]);
+  }
+}
+
+void checkNoLeak12(int tag) {
+  mx_handle_t sa, sb;
+  if (mx_channel_create(0, &sa, &sb) < 0) {
+    return;
+  }
+  if (tag) {
+    escapeMethod(&sa);
+    escapeMethod(&sb);
+  }
+  mx_handle_close(sa);
+  mx_handle_close(sb);
+}
+
+void checkLeak01() {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+} // expected-warning {{Allocated handle is never released; potential resource leak}}
+
+void checkLeak02(int tag) {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  if (tag) {
+    mx_handle_close(sa);
+  }
+  mx_handle_close(sb); // expected-warning {{Allocated handle is never released; potential resource leak}}
+}
+
+void checkLeak03(mx_handle_t handle) {
+  mx_handle_t handlebuf[4];
+  uint32_t hcount;
+  mx_status_t r = mx_channel_read(handle, 0, NULL, handlebuf, 0, 4, 0, &hcount);
+  if (r < 0) {
+    return;
+  }
+  for (int i = 0; i < hcount -1; i++) {
+    mx_handle_close(handlebuf[i]);
+  }
+} // expected-warning {{Allocated handle is never released; potential resource leak}}
+
+void checkLeak04(mx_handle_t handle) {
+  mx_handle_t handlebuf[3];
+  uint32_t hcount;
+  mx_status_t r = mx_channel_read(handle, 0, NULL, handlebuf, 0, 3, 0, &hcount);
+  if (r < 0) {
+    return;
+  }
+  if (mx_channel_write(handle, 0, NULL, 0, handlebuf, hcount - 1) < 0) {
+    for (int i = 0; i < hcount; i++) {
+      mx_handle_close(handlebuf[i]);
+    }
+  }
+} // expected-warning {{Allocated handle is never released; potential resource leak}}
+
+void checkLeak05(mx_handle_t handle, uint32_t hcount) {
+  mx_handle_t handlebuf[6];
+  mx_status_t r = mx_channel_read(
+                  handle, 0, NULL, handlebuf, 0, hcount, 0, &hcount);
+  if (r < 0) {
+    return;
+  }
+  if (mx_channel_write(handle, 0, NULL, 0, handlebuf, hcount - 1) < 0) {
+    for (int i = 0; i < hcount; i++) {
+      mx_handle_close(handlebuf[i]);
+    }
+  }
+} // expected-warning {{Allocated handle is never released; potential resource leak}}
+
+void checkLeak06(mx_handle_t handle, uint32_t hcount) {
+  mx_handle_t handlebuf[6];
+  mx_channel_read(handle, 0, NULL, handlebuf, 0, hcount, 0, &hcount);
+  mx_channel_write(handle, 0, NULL, 0, handlebuf, hcount); // It may fail and handles are not released.
+} // expected-warning {{Allocated handle is never released; potential resource leak}}
+
+void checkDoubleRelease01(int tag) {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  if (tag) {
+    mx_handle_close(sa);
+  }
+  mx_handle_close(sa); // expected-warning {{Releasing a previously released handle}}
+  mx_handle_close(sb);
+}
+
+void checkUseAfterFree01(int tag) {
+  mx_handle_t sa, sb;
+  mx_channel_create(0, &sa, &sb);
+  if (tag) {
+    mx_handle_close(sa);
+  }
+  useHandle(sa); // expected-warning {{Using a previously released handle}}
+  mx_handle_close(sa);
+  mx_handle_close(sb);
+}
Index: lib/StaticAnalyzer/Checkers/MagentaHandleChecker.cpp
===================================================================
--- /dev/null
+++ lib/StaticAnalyzer/Checkers/MagentaHandleChecker.cpp
@@ -0,0 +1,928 @@
+//== MagentaHandleChecker.cpp - Magenta Handle Checker------------*- C++-*--==//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This checker checks if the handle of magenta kernel is properly used
+// according to following rules.
+//   - If a handle is allocated, it should be closed/released before execution
+//        ends.
+//   - If a handle is closed/released, it should not be closed/released again.
+//   - If a handle is closed/released, it should not be used for other purposes
+//        such as I/O.
+//
+// In this checker, each tracked handle is associated with a state. When the
+// handle variable is passed to different function calls or syscalls, its state
+// changes. As illustrated in the following ASCII Art:
+//
+//                          mx_channel_write failed
+//                                +---------+
+//                                |         |
+//                                |         |
+//                                |         |      As argument
+//  mx_channel_create succeeded +-+---------v-+    in uninlined   +---------+
+//  mx_channel_read succeeded   |             |    calls          |         |
+//            +----------------->  Allocated  +-------------------> Escaped |
+//            |                 |             |     As return     |         |
+//            |                 +-----+------++     value or      +---------+
+//            |                       |      |      assigned
+//            |       mx_handle_close |      |      back to argument.
+//            |       mx_channel_write|      +--+
+//            |        succeeded      |         |handle out+--------+
+//            |                  +----v-----+   |of scope  |        |
+//            |                  |          |   +----------> Leaked |
+// +----------+--+               | Released |              |(REPORT)|
+// |             |               |          |              +--------+
+// | Not tracked <--+            +----+---+-+
+// |             |  |                 |   |       As argument
+// +------+------+  |  mx_handle_close|   +------+in function
+//        |         |                 |          |call
+//        |         |            +----v-----+    |     +-----------+
+//        +---------+            |          |    |     |           |
+//    mx_channel_create failed   | Double   |    +-----> Use after |
+//    mx_channel_read failed     | released |          | released  |
+//                               | (REPORT) |          | (REPORT)  |
+//                               +----------+          +-----------+
+//
+//
+// If a tracked handle ends up in "Released" or "Escaped" state, we assume it
+// is properly used. Otherwise a bug will be reported.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangSACheckers.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/ParentMap.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include <climits>
+#include <limits.h>
+#include <stdio.h>
+#include <string>
+#include <utility>
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+enum CallKind {
+  // Will add more calls in the future. For now only worried about the ones
+  // related to channel creation.
+  MX_CHANNEL_CREATE,
+  MX_CHANNEL_READ,
+  MX_CHANNEL_WRITE,
+  MX_HANDLE_CLOSE,
+  UNRELATED_CALL
+};
+
+struct HandleState {
+private:
+  enum Kind {
+    // Handle is allocated
+    Allocated,
+    // Handle is released
+    Released,
+    // Handle is no longer trackable
+    Escaped
+  } K;
+
+  HandleState(Kind k) : K(k) {}
+
+public:
+  bool operator==(const HandleState &X) const { return K == X.K; }
+  bool isAllocated() const { return K == Allocated; }
+  bool isReleased() const { return K == Released; }
+  bool isEscaped() const { return K == Escaped; }
+
+  static HandleState getAllocated() { return HandleState(Allocated); }
+
+  static HandleState getReleased() { return HandleState(Released); }
+
+  static HandleState getEscaped() { return HandleState(Escaped); }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
+};
+
+class MagentaHandleChecker
+    : public Checker<check::DeadSymbols, check::PreCall,
+                     check::PreStmt<ReturnStmt>, check::PointerEscape,
+                     eval::Call, check::PostCall> {
+  std::unique_ptr<BugType> LeakBugType;
+  std::unique_ptr<BugType> DoubleReleaseBugType;
+  std::unique_ptr<BugType> UseAfterFreeBugType;
+  mutable llvm::StringMap<CallKind> FunctionNameMap;
+
+public:
+  MagentaHandleChecker();
+  // Checker callbacks
+  void checkPreCall(const CallEvent &Call, CheckerContext &Ctx) const;
+
+  void checkPostCall(const CallEvent &Call, CheckerContext &Ctx) const;
+
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &Ctx) const;
+
+  void checkPreStmt(const ReturnStmt *RS, CheckerContext &Ctx) const;
+
+  bool evalCall(const CallExpr *CE, CheckerContext &Ctx) const;
+
+  ProgramStateRef checkPointerEscape(ProgramStateRef State,
+                                     const InvalidatedSymbols &Escaped,
+                                     const CallEvent *Call,
+                                     PointerEscapeKind Kind) const;
+
+private:
+  bool processMxChannelRead(const CallExpr *CE, CheckerContext &C) const;
+
+  bool processMxChannelCreate(const CallExpr *CE, CheckerContext &C) const;
+
+  bool processMxChannelWrite(const CallExpr *CE, CheckerContext &C) const;
+
+  void processMxHandleClose(ProgramStateRef State, const CallEvent &Call,
+                            CheckerContext &Ctx) const;
+
+  void processUninlinedCalls(ProgramStateRef State, const CallEvent &Call,
+                             CheckerContext &Ctx) const;
+
+  ProgramStateRef conjureFailedState(const CallExpr *CE, ProgramStateRef State,
+                                     CheckerContext &Ctx) const;
+
+  // Bug report functions
+  void reportLeaks(ArrayRef<SymbolRef> LeakedHandles, CheckerContext &Ctx,
+                   ExplodedNode *ErrorNode) const;
+
+  void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range,
+                           CheckerContext &Ctx) const;
+
+  void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range,
+                          CheckerContext &Ctx) const;
+  // Utility functions
+  CallKind CheckCallSignature(const CallEvent &Call) const;
+
+  CallKind CheckCallSignature(const FunctionDecl *FuncDecl) const;
+
+  bool CheckExprIsZero(const Expr *ArgExpr, CheckerContext &Ctx) const;
+
+  int64_t getArgValueFromExpr(const Expr *ArgExpr, ProgramStateRef State,
+                              const LocationContext *LCtx,
+                              int64_t DefaultVal) const;
+
+  SymbolRef getParentSymbolFromElementRegion(const ElementRegion *EleRegion,
+                                             ProgramStateRef State) const;
+
+  ProgramStateRef allocateSingleHandle(const Expr *ArgExpr,
+                                       const LocationContext *LCtx,
+                                       ProgramStateRef State) const;
+
+  ProgramStateRef allocateHandlesForArray(int HandleCount,
+                                          ProgramStateRef State,
+                                          CheckerContext &Ctx, QualType EleType,
+                                          SymbolRef ParentSymbol,
+                                          const SubRegion *SuperRegion) const;
+
+  ProgramStateRef releaseHandlesForArray(int HandleCount, const CallExpr *CE,
+                                         ProgramStateRef State,
+                                         CheckerContext &Ctx, QualType EleType,
+                                         SymbolRef ParentSymbol,
+                                         const SubRegion *SuperRegion) const;
+
+  ProgramStateRef releaseAssociatedHandles(const CallExpr *CE,
+                                           ProgramStateRef State,
+                                           CheckerContext &Ctx,
+                                           SymbolRef ParentSymbol) const;
+
+  // Return true only if it is certain that Sym will be Zero
+  static bool CheckSymbolConstraintToZero(SymbolRef Sym, ProgramStateRef State);
+
+  bool isLeaked(SymbolRef SymHandle, const HandleState &CurHandleState,
+                bool isSymDead, ProgramStateRef State) const;
+};
+} // end anonymous namespace
+
+// Handle -> HandleState map
+REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState)
+
+MagentaHandleChecker::MagentaHandleChecker() {
+  // Initialize the bug types.
+  LeakBugType.reset(
+      new BugType(this, "MX handle leak", "Magenta Handle Error"));
+  DoubleReleaseBugType.reset(
+      new BugType(this, "MX handle double release", "Magenta Handle Error"));
+  UseAfterFreeBugType.reset(
+      new BugType(this, "MX handle use after free", "Magenta Handle Error"));
+
+  FunctionNameMap = {{"mx_channel_create", MX_CHANNEL_CREATE},
+                     {"mx_channel_read", MX_CHANNEL_READ},
+                     {"mx_handle_close", MX_HANDLE_CLOSE},
+                     {"mx_channel_write", MX_CHANNEL_WRITE}};
+}
+
+CallKind
+MagentaHandleChecker::CheckCallSignature(const FunctionDecl *FuncDecl) const {
+  if (!FuncDecl)
+    return UNRELATED_CALL;
+
+  DeclarationName DeclName = FuncDecl->getDeclName();
+  if (!DeclName.isIdentifier())
+    return UNRELATED_CALL;
+
+  // Use function name to match target function calls
+  // Type signature check is not necessary because C function
+  // cannot be overridden
+  // An annotation based matching system is work in progress.
+  StringRef FuncName = FuncDecl->getName();
+  if (FunctionNameMap.count(FuncName) != 1)
+    return UNRELATED_CALL;
+  return FunctionNameMap[FuncName];
+}
+
+CallKind MagentaHandleChecker::CheckCallSignature(const CallEvent &Call) const {
+  if (const AnyFunctionCall *FuncCall = dyn_cast<AnyFunctionCall>(&Call)) {
+    const FunctionDecl *FuncDecl = FuncCall->getDecl();
+    if (!FuncDecl)
+      return UNRELATED_CALL;
+
+    return CheckCallSignature(FuncDecl);
+  }
+  return UNRELATED_CALL;
+}
+
+bool MagentaHandleChecker::isLeaked(SymbolRef SymHandle,
+                                    const HandleState &CurHandleState,
+                                    bool isSymDead,
+                                    ProgramStateRef State) const {
+  if (isSymDead && CurHandleState.isAllocated()) {
+    // Check if handle value is MX_HANDLE_INVALID. If so, not a leak.
+    if (CheckSymbolConstraintToZero(SymHandle, State))
+      return false;
+
+    // Handle is allocated and dead. Leaked
+    return true;
+  }
+  // Handle not dead. Not a leak.
+  return false;
+}
+
+bool MagentaHandleChecker::CheckSymbolConstraintToZero(SymbolRef Sym,
+                                                       ProgramStateRef State) {
+  ConstraintManager &CMgr = State->getConstraintManager();
+  ConditionTruthVal IsZero = CMgr.isNull(State, Sym);
+  if (IsZero.isConstrained()) {
+    // The value can be compared to zero
+    if (IsZero.isConstrainedTrue())
+      return true;
+  }
+  return false;
+}
+
+ProgramStateRef MagentaHandleChecker::checkPointerEscape(
+    ProgramStateRef State, const InvalidatedSymbols &Escaped,
+    const CallEvent *Call, PointerEscapeKind Kind) const {
+  HStateMapTy TrackedHandle = State->get<HStateMap>();
+  SmallVector<SymbolRef, 2> EscapedSymbolRef;
+  for (auto &CurItem : TrackedHandle) {
+    SymbolRef Sym = CurItem.first;
+    if (Escaped.count(Sym) == 1)
+      EscapedSymbolRef.push_back(Sym);
+
+    const SymbolDerived *ElementSym = dyn_cast<SymbolDerived>(Sym);
+    if (!ElementSym)
+      continue;
+
+    const SymbolRef ParentSymbol = ElementSym->getParentSymbol();
+    if (Escaped.count(ParentSymbol) == 1)
+      EscapedSymbolRef.push_back(Sym);
+  }
+
+  for (SymbolRef EscapedHandle : EscapedSymbolRef) {
+    State = State->remove<HStateMap>(EscapedHandle);
+    State = State->set<HStateMap>(EscapedHandle, HandleState::getEscaped());
+  }
+
+  return State;
+}
+
+bool MagentaHandleChecker::CheckExprIsZero(const Expr *ArgExpr,
+                                           CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  const LocationContext *LCtx = Ctx.getLocationContext();
+  SVal ExprSVal = State->getSVal(ArgExpr, LCtx);
+  Optional<DefinedOrUnknownSVal> DSVal = ExprSVal.getAs<DefinedOrUnknownSVal>();
+  if (DSVal.hasValue())
+    return !State->assume(DSVal.getValue(), true);
+
+  return false;
+}
+
+void MagentaHandleChecker::checkPreCall(const CallEvent &Call,
+                                        CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  if (CheckCallSignature(Call) == MX_HANDLE_CLOSE)
+    processMxHandleClose(State, Call, Ctx);
+}
+
+void MagentaHandleChecker::checkPostCall(const CallEvent &Call,
+                                         CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  if (CheckCallSignature(Call) == UNRELATED_CALL)
+    processUninlinedCalls(State, Call, Ctx);
+}
+
+void MagentaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+                                            CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  SmallVector<SymbolRef, 2> LeakVector;
+  HStateMapTy TrackedHandle = State->get<HStateMap>();
+  for (auto &CurItem : TrackedHandle) {
+    SymbolRef Sym = CurItem.first;
+    // Workaround for zombie symbol issue.
+    bool IsSymDead = SymReaper.maybeDead(Sym);
+    const HandleState &CurHandleState = CurItem.second;
+    if (isLeaked(Sym, CurHandleState, IsSymDead, State))
+      LeakVector.push_back(Sym);
+
+    if (IsSymDead)
+      State = State->remove<HStateMap>(Sym);
+  }
+  if (!LeakVector.empty()) {
+    ExplodedNode *N = Ctx.generateNonFatalErrorNode(State);
+    if (!N)
+      return;
+
+    reportLeaks(LeakVector, Ctx, N);
+  }
+  Ctx.addTransition(State);
+}
+
+void MagentaHandleChecker::checkPreStmt(const ReturnStmt *RS,
+                                        CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  const auto *LCtx = Ctx.getLocationContext();
+  if (!LCtx)
+    return;
+
+  const auto *SFCtx = LCtx->getCurrentStackFrame();
+  if (!SFCtx || SFCtx->inTopFrame())
+    return;
+
+  const Expr *RetE = RS->getRetValue();
+  if (!RetE)
+    return;
+
+  SVal SValRet = State->getSVal(RetE, LCtx);
+  SymbolRef SymRet = SValRet.getAsSymbol();
+  if (!SymRet)
+    return;
+
+  const HandleState *SymState = State->get<HStateMap>(SymRet);
+  // Check if value returned in this ReturnStmt is tracked by analyzer
+  if (!SymState)
+    return;
+
+  if (SymState->isReleased()) {
+    // Use after release bug.
+    ExplodedNode *N = Ctx.generateErrorNode(State);
+    if (!N)
+      return;
+
+    reportUseAfterFree(SymRet, RS->getSourceRange(), Ctx);
+    return;
+  }
+  State = State->set<HStateMap>(SymRet, HandleState::getEscaped());
+  Ctx.addTransition(State);
+}
+
+bool MagentaHandleChecker::evalCall(const CallExpr *CE,
+                                    CheckerContext &C) const {
+  const FunctionDecl *FuncDecl = C.getCalleeDecl(CE);
+  switch (CheckCallSignature(FuncDecl)) {
+  case MX_CHANNEL_READ:
+    return processMxChannelRead(CE, C);
+  case MX_CHANNEL_CREATE:
+    return processMxChannelCreate(CE, C);
+  case MX_CHANNEL_WRITE:
+    return processMxChannelWrite(CE, C);
+  default:
+    break;
+  }
+  return false;
+}
+
+void MagentaHandleChecker::processUninlinedCalls(ProgramStateRef State,
+                                                 const CallEvent &Call,
+                                                 CheckerContext &Ctx) const {
+  // Process the handle escaped situation.
+  // When a function is not inlined for any reasons, if one of its
+  // arguments is an acquired handle, treat it as an escaped handle.
+  // This is just a naive approach to reduce the false positive rate, should
+  // be refined later, e.g. through annotation
+  // Annotation based system is work in progress.
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+  if (!FD)
+    return;
+
+  if (Ctx.wasInlined)
+    return;
+
+  unsigned ArgsCount = Call.getNumArgs();
+  bool StateChanged = false;
+  if (!ArgsCount)
+    // No argument passed to this call, ignore it
+    return;
+  for (unsigned i = 0; i < ArgsCount; i++) {
+    SVal ArgSVal = Call.getArgSVal(i);
+    SymbolRef ArgSym = ArgSVal.getAsSymbol();
+    // Check if the argument is a pointer. If so, it should have been handled
+    // by checkPointerEscape, can be ignored here.
+    if (!ArgSym)
+      continue;
+
+    const HandleState *CurHandleState = State->get<HStateMap>(ArgSym);
+    // Check if the handle is tracked by analyzer. If not, we ignore it here.
+    if (!CurHandleState)
+      continue;
+
+    if (CurHandleState->isReleased())
+      // Use after free
+      reportUseAfterFree(ArgSym, Call.getSourceRange(), Ctx);
+    State = State->set<HStateMap>(ArgSym, HandleState::getEscaped());
+    StateChanged = true;
+  }
+  if (StateChanged)
+    Ctx.addTransition(State);
+}
+
+// This function process calls to syscall
+// mx_status_t mx_channel_read(mx_handle_t handle, uint32_t options,
+//                            void* bytes, mx_handle_t* handles,
+//                            uint32_t num_bytes, uint32_t num_handles,
+//                            uint32_t* actual_bytes, uint32_t* actual_handles);
+bool MagentaHandleChecker::processMxChannelRead(const CallExpr *CE,
+                                                CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  const LocationContext *LCtx = Ctx.getLocationContext();
+  SValBuilder &svalBuilder = Ctx.getSValBuilder();
+
+  // Check if handle related args are nullptr or 0. If so, do not process
+  // this call.
+  const Expr *HandleBufExpr = CE->getArg(3);
+  const Expr *InputSizeExpr = CE->getArg(5);
+  const Expr *OutputSizeExpr = CE->getArg(7);
+  if (CheckExprIsZero(HandleBufExpr, Ctx) ||
+      CheckExprIsZero(InputSizeExpr, Ctx) ||
+      CheckExprIsZero(OutputSizeExpr, Ctx))
+    return false;
+
+  // this syscall may fail during runtime, bifurcate the state here.
+  ProgramStateRef FailedState = conjureFailedState(CE, State, Ctx);
+
+  // Invalidate the handlebuf pointer and handle_count pointer
+  SmallVector<SVal, 2> InvalidateSVal;
+  InvalidateSVal.push_back(State->getSVal(HandleBufExpr, LCtx));
+  InvalidateSVal.push_back(State->getSVal(OutputSizeExpr, LCtx));
+  State = State->invalidateRegions(InvalidateSVal, CE, Ctx.blockCount(), LCtx,
+                                   false, nullptr, nullptr, nullptr);
+  // Conjure a successful state with return value is 0
+  SVal StatusSVal = svalBuilder.makeIntVal(llvm::APSInt::get(0));
+  State = State->BindExpr(CE, LCtx, StatusSVal);
+
+  const MemRegion *MemHandleBuf =
+      State->getSVal(HandleBufExpr, LCtx).getAsRegion();
+  if (!MemHandleBuf)
+    return false;
+
+  // Determine how many handles should be allocated, it may have following
+  // cases:
+  // 1. handlebuf is a pointer to a local variable, allocate 1 handle.
+  // 2. handlebuf is an array and InputSizeExpr can be resolved to a concrete
+  //    int, denoted as inputsize. If 0 < inputsize <= 4, allocate
+  //    exact number of handles as indicated by inputsize. If inputsize <= 0,
+  //    consider it as an error and fallback to conservativeEvalCall. If
+  //    inputsize > 4, assign 4 to inputsize.
+  // 3. handlebuf is an array and InputSizeExpr cannot be resolved to a concrete
+  //    integer. In this case, assume inputsize is 4 and do the same thing as
+  //    condition 2
+  int64_t ExtVal = getArgValueFromExpr(InputSizeExpr, State, LCtx, 4);
+  if (ExtVal < 0)
+    return false;
+  if (!isa<ElementRegion>(MemHandleBuf)) {
+    if (isa<VarRegion>(MemHandleBuf)) {
+      // It is condition 1
+      State = allocateSingleHandle(HandleBufExpr, LCtx, State);
+      ExtVal = 1;
+    } else {
+      // Unknown condition
+      return false;
+    }
+  } else {
+    if (ExtVal > 4)
+      ExtVal = 4;
+    // It is condition 2 or 3
+    const ElementRegion *EleRegion = dyn_cast<ElementRegion>(MemHandleBuf);
+    SymbolRef ParentSymbol = getParentSymbolFromElementRegion(EleRegion, State);
+    if (!ParentSymbol)
+      return false;
+
+    const SubRegion *SuperRegionSub =
+        dyn_cast<SubRegion>(EleRegion->getSuperRegion());
+    // ElementRegion is a child of TypedValueRegion. Get the type.
+    QualType HandleType = cast<TypedValueRegion>(MemHandleBuf)->getValueType();
+    State = allocateHandlesForArray(ExtVal, State, Ctx, HandleType,
+                                    ParentSymbol, SuperRegionSub);
+    if (!State)
+      return false;
+  }
+  // Process the actual_handle returned
+  SVal ActHandleSVal = State->getSVal(OutputSizeExpr, LCtx);
+  SVal ConcreteInvSVal = svalBuilder.makeIntVal(llvm::APSInt::get(ExtVal));
+  State = State->bindLoc(ActHandleSVal, ConcreteInvSVal, LCtx);
+
+  Ctx.addTransition(State);
+  Ctx.addTransition(FailedState);
+  return true;
+}
+
+// This function process calls to syscall
+// mx_status_t mx_channel_create(uint32_t options,
+//                               mx_handle_t* out0, mx_handle_t* out1);
+bool MagentaHandleChecker::processMxChannelCreate(const CallExpr *CE,
+                                                  CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  const LocationContext *LCtx = Ctx.getLocationContext();
+  const Expr *Handle1Expr = CE->getArg(1);
+  const Expr *Handle2Expr = CE->getArg(2);
+  if (!(Handle1Expr && Handle2Expr))
+    return false;
+
+  // Conjure a failed state with no handle allocated and status less than 0
+  ProgramStateRef FailedState = conjureFailedState(CE, State, Ctx);
+
+  // Invalidate handle pointers and conjure a successful state with status = 0
+  SmallVector<SVal, 2> invalidateSVal;
+  invalidateSVal.push_back(State->getSVal(Handle1Expr, LCtx));
+  invalidateSVal.push_back(State->getSVal(Handle2Expr, LCtx));
+
+  State = State->invalidateRegions(invalidateSVal, CE, Ctx.blockCount(), LCtx,
+                                   false, nullptr, nullptr, nullptr);
+  SVal StatusSVal = Ctx.getSValBuilder().makeIntVal(llvm::APSInt::get(0));
+  State = State->BindExpr(CE, LCtx, StatusSVal);
+
+  State = allocateSingleHandle(Handle1Expr, LCtx, State);
+  if (!State)
+    return false;
+
+  State = allocateSingleHandle(Handle2Expr, LCtx, State);
+  if (!State)
+    return false;
+
+  Ctx.addTransition(State);
+  Ctx.addTransition(FailedState);
+  return true;
+}
+
+ProgramStateRef
+MagentaHandleChecker::allocateSingleHandle(const Expr *ArgExpr,
+                                           const LocationContext *LCtx,
+                                           ProgramStateRef State) const {
+  if (!State || !LCtx)
+    return nullptr;
+  SVal ArgSVal = State->getSVal(ArgExpr, LCtx);
+  // It is a pointer, so get the mem region first.
+  const MemRegion *MemHandle = ArgSVal.getAsRegion();
+  if (!MemHandle)
+    return nullptr;
+
+  SVal SValHandle = State->getSVal(MemHandle);
+  SymbolRef SymHandle = SValHandle.getAsSymbol();
+  if (!SymHandle)
+    return nullptr;
+
+  DefinedOrUnknownSVal DSValHandle = SValHandle.castAs<DefinedOrUnknownSVal>();
+  if (DSValHandle.getBaseKind() == SVal::NonLocKind)
+    // Allocated handle should be larger than 0
+    State->assumeInclusiveRange(DSValHandle, llvm::APSInt::get(1),
+                                llvm::APSInt::get(INT_MAX), true);
+
+  HandleState HS = HandleState::getAllocated();
+  return State->set<HStateMap>(SymHandle, HS);
+}
+
+ProgramStateRef MagentaHandleChecker::allocateHandlesForArray(
+    int HandleCount, ProgramStateRef State, CheckerContext &Ctx,
+    QualType EleType, SymbolRef ParentSymbol,
+    const SubRegion *SuperRegion) const {
+
+  SValBuilder &Bldr = Ctx.getSValBuilder();
+  MemRegionManager &MemRegionMgr = Bldr.getRegionManager();
+  ASTContext &ASTCtx = State->getStateManager().getContext();
+  for (int i = 0; i < HandleCount; ++i) {
+    NonLoc AryIndex = Bldr.makeArrayIndex(i);
+    const ElementRegion *CurElementRegion =
+        MemRegionMgr.getElementRegion(EleType, AryIndex, SuperRegion, ASTCtx);
+    if (!CurElementRegion)
+      return nullptr;
+    // Build derived SVal for elements in the handle buffer
+    DefinedOrUnknownSVal CurSVal =
+        Bldr.getDerivedRegionValueSymbolVal(ParentSymbol, CurElementRegion);
+    SymbolRef CurSymbol = CurSVal.getAsSymbol();
+    if (!CurSymbol)
+      return nullptr;
+    // A valid handle should be larger than 0. Add this constraint to the handle
+    if (CurSVal.getBaseKind() == SVal::NonLocKind)
+      State->assumeInclusiveRange(CurSVal, llvm::APSInt::get(1),
+                                  llvm::APSInt::get(INT_MAX), true);
+    HandleState HS = HandleState::getAllocated();
+    State = State->set<HStateMap>(CurSymbol, HS);
+  }
+  return State;
+}
+
+// This function process calls to syscall
+// mx_status_t mx_channel_write(mx_handle_t handle, uint32_t options,
+//                              void* bytes, uint32_t num_bytes,
+//                              mx_handle_t* handles, uint32_t num_handles)
+bool MagentaHandleChecker::processMxChannelWrite(const CallExpr *CE,
+                                                 CheckerContext &Ctx) const {
+  ProgramStateRef State = Ctx.getState();
+  const LocationContext *LCtx = Ctx.getLocationContext();
+  SValBuilder &svalBuilder = Ctx.getSValBuilder();
+
+  // If handle related arguments are 0, do not process this call
+  const Expr *HandleBufExpr = CE->getArg(4);
+  const Expr *InputSizeExpr = CE->getArg(5);
+  if (CheckExprIsZero(HandleBufExpr, Ctx) ||
+      CheckExprIsZero(InputSizeExpr, Ctx))
+    return false;
+
+  // this syscall may fail during runtime, bifurcate the state here.
+  ProgramStateRef FailedState = conjureFailedState(CE, State, Ctx);
+  // Conjure a successful state
+  SVal StatusSVal = svalBuilder.makeIntVal(llvm::APSInt::get(0));
+  State = State->BindExpr(CE, LCtx, StatusSVal);
+
+  // Determine how many handles should be released. it may have following
+  // cases:
+  // 1. handlebuf is a pointer to a local mx_handle_t variable, only 1 handle
+  //    should be released
+  // 2. handlebuf is an array and InputSizeExpr can be resolved to a concrete
+  //    int, let's denote it as inputsize. If 0 < inputsize <= 4, release
+  //    exact number of handles as indicated by inputsize. If inputsize <= 0,
+  //    consider it as an error and fallback to conservativeEvalCall. If
+  //    inputsize > 4 it is case 3.
+  // 3. handlebuf is an array and inputsize is larger than 4 or cannot be
+  //    resolved to concrete int, release all handles that are associated with
+  //    handlebuf.
+  int64_t ExtVal = getArgValueFromExpr(InputSizeExpr, State, LCtx, -1);
+  // Retrive MemRegion of the handle buffer
+  SVal HandleBufSValOrig = State->getSVal(HandleBufExpr, LCtx);
+  const MemRegion *MemHandleBuf = HandleBufSValOrig.getAsRegion();
+  bool TransitionHappened = false;
+  if (!isa<ElementRegion>(MemHandleBuf)) {
+    if (isa<VarRegion>(MemHandleBuf)) {
+      // It is condition 1
+      ExtVal = 1;
+      SVal HandleBufSVal = State->getSVal(MemHandleBuf);
+      SymbolRef SymHandleBuf = HandleBufSVal.getAsSymbol();
+      if (!SymHandleBuf)
+        return false;
+      const HandleState *HS = State->get<HStateMap>(SymHandleBuf);
+      if (HS) {
+        if (HS->isReleased()) {
+          reportDoubleRelease(SymHandleBuf, CE->getSourceRange(), Ctx);
+        } else {
+          State =
+              State->set<HStateMap>(SymHandleBuf, HandleState::getReleased());
+        }
+      }
+    } else {
+      // Unknown condition
+      return false;
+    }
+  } else {
+    // Condition 2 or 3.
+    const ElementRegion *EleRegion = dyn_cast<ElementRegion>(MemHandleBuf);
+    SymbolRef ParentSymbol = getParentSymbolFromElementRegion(EleRegion, State);
+    if (!ParentSymbol)
+      return false;
+    const SubRegion *SuperRegionSub =
+        dyn_cast<SubRegion>(EleRegion->getSuperRegion());
+    QualType HandleType = cast<TypedValueRegion>(MemHandleBuf)->getValueType();
+
+    if (ExtVal < 0 || ExtVal > 5) {
+      // Condition 2
+      ProgramStateRef NewState =
+          releaseAssociatedHandles(CE, State, Ctx, ParentSymbol);
+      if (!NewState && NewState != State) {
+        State = NewState;
+        TransitionHappened = true;
+      }
+    } else {
+      // Condition 3
+      ProgramStateRef NewState = releaseHandlesForArray(
+          ExtVal, CE, State, Ctx, HandleType, ParentSymbol, SuperRegionSub);
+      if (!NewState)
+        return false;
+      if (NewState != State)
+        TransitionHappened = true;
+      State = NewState;
+    }
+  }
+
+  if (TransitionHappened)
+    Ctx.addTransition(State);
+  Ctx.addTransition(FailedState);
+  return true;
+}
+
+ProgramStateRef MagentaHandleChecker::releaseHandlesForArray(
+    int HandleCount, const CallExpr *CE, ProgramStateRef State,
+    CheckerContext &Ctx, QualType EleType, SymbolRef ParentSymbol,
+    const SubRegion *SuperRegion) const {
+  SValBuilder &Bldr = Ctx.getSValBuilder();
+  MemRegionManager &MemRegionMgr = Bldr.getRegionManager();
+  ASTContext &ASTCtx = State->getStateManager().getContext();
+  for (int i = 0; i < HandleCount; ++i) {
+    NonLoc AryIndex = Bldr.makeArrayIndex(i);
+    const ElementRegion *CurElementRegion =
+        MemRegionMgr.getElementRegion(EleType, AryIndex, SuperRegion, ASTCtx);
+    if (!CurElementRegion)
+      return nullptr;
+    // Build derived SVal for elements in the handle buffer
+    DefinedOrUnknownSVal CurSVal =
+        Bldr.getDerivedRegionValueSymbolVal(ParentSymbol, CurElementRegion);
+    SymbolRef CurSymbol = CurSVal.getAsSymbol();
+    if (!CurSymbol)
+      return nullptr;
+
+    const HandleState *SymState = State->get<HStateMap>(CurSymbol);
+    if (!SymState)
+      continue;
+
+    if (SymState->isReleased()) {
+      reportDoubleRelease(CurSymbol, CE->getSourceRange(), Ctx);
+    } else {
+      State = State->set<HStateMap>(CurSymbol, HandleState::getReleased());
+    }
+  }
+  return State;
+}
+
+ProgramStateRef MagentaHandleChecker::releaseAssociatedHandles(
+    const CallExpr *CE, ProgramStateRef State, CheckerContext &Ctx,
+    SymbolRef ParentSymbol) const {
+  HStateMapTy TrackedHandle = State->get<HStateMap>();
+  for (auto &CurItem : TrackedHandle) {
+    SymbolRef Sym = CurItem.first;
+    HandleState CurHandleState = CurItem.second;
+    const SymbolDerived *ElementSym = dyn_cast<SymbolDerived>(Sym);
+    if (!ElementSym)
+      continue;
+
+    if (ElementSym->getParentSymbol() == ParentSymbol) {
+      if (CurHandleState.isReleased()) {
+        // Double release
+        reportDoubleRelease(Sym, CE->getSourceRange(), Ctx);
+      } else {
+        State = State->set<HStateMap>(Sym, HandleState::getReleased());
+      }
+    }
+  }
+  return State;
+}
+
+SymbolRef MagentaHandleChecker::getParentSymbolFromElementRegion(
+    const ElementRegion *EleRegion, ProgramStateRef State) const {
+  if (!EleRegion || !State)
+    return nullptr;
+
+  const SubRegion *SuperRegionSub =
+      dyn_cast<SubRegion>(EleRegion->getSuperRegion());
+  if (!SuperRegionSub)
+    return nullptr;
+
+  SVal HandleBufSVal = State->getSVal(EleRegion);
+  SymbolRef SymHandleBuf = HandleBufSVal.getAsSymbol();
+  if (!SymHandleBuf)
+    return nullptr;
+
+  // Rare condition. There are some cases that the member of array is not
+  // SymbolDerived types.
+  if (!isa<SymbolDerived>(SymHandleBuf))
+    return nullptr;
+
+  SymbolRef ParentSymbol =
+      dyn_cast<SymbolDerived>(SymHandleBuf)->getParentSymbol();
+  return ParentSymbol;
+}
+// This function process calls to syscall
+//    mx_status_t mx_handle_close(mx_handle_t handle);
+void MagentaHandleChecker::processMxHandleClose(ProgramStateRef State,
+                                                const CallEvent &Call,
+                                                CheckerContext &Ctx) const {
+  // Retrive symbolic value for passed in handle
+  SymbolRef SymHandle = Call.getArgSVal(0).getAsSymbol();
+  if (!SymHandle)
+    return;
+
+  const HandleState *SymState = State->get<HStateMap>(SymHandle);
+  if (!SymState)
+    return;
+
+  if (SymState->isReleased()) {
+    // Double release
+    reportDoubleRelease(SymHandle, Call.getSourceRange(), Ctx);
+    return;
+  }
+  State = State->set<HStateMap>(SymHandle, HandleState::getReleased());
+  Ctx.addTransition(State);
+}
+
+// When a magenta syscall failed. It will return an integer less than 0.
+ProgramStateRef MagentaHandleChecker::conjureFailedState(
+    const CallExpr *CE, ProgramStateRef State, CheckerContext &Ctx) const {
+  const LocationContext *LCtx = Ctx.getLocationContext();
+  DefinedOrUnknownSVal FailedSVal = Ctx.getSValBuilder().conjureSymbolVal(
+      nullptr, CE, LCtx, Ctx.blockCount());
+  ProgramStateRef FailedState = State->BindExpr(CE, LCtx, FailedSVal);
+  FailedState = FailedState->assumeInclusiveRange(
+      FailedSVal, llvm::APSInt::get(INT_MIN), llvm::APSInt::get(-1), true);
+  return FailedState;
+}
+
+int64_t MagentaHandleChecker::getArgValueFromExpr(const Expr *ArgExpr,
+                                                  ProgramStateRef State,
+                                                  const LocationContext *LCtx,
+                                                  int64_t DefaultVal) const {
+  int64_t ExtVal = DefaultVal;
+  SVal InputSizeSVal = State->getSVal(ArgExpr, LCtx);
+  if (InputSizeSVal.getBaseKind() == SVal::NonLocKind &&
+      InputSizeSVal.getSubKind() == nonloc::ConcreteIntKind) {
+    ExtVal =
+        InputSizeSVal.castAs<nonloc::ConcreteInt>().getValue().getExtValue();
+  } else if (InputSizeSVal.getBaseKind() == SVal::LocKind &&
+             InputSizeSVal.getSubKind() == loc::ConcreteIntKind) {
+    ExtVal = InputSizeSVal.castAs<loc::ConcreteInt>().getValue().getExtValue();
+  }
+  return ExtVal;
+}
+
+void MagentaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles,
+                                       CheckerContext &C,
+                                       ExplodedNode *ErrorNode) const {
+  for (SymbolRef LeakedHandle : LeakedHandles) {
+    auto R = llvm::make_unique<BugReport>(
+        *LeakBugType,
+        "Allocated handle is never released; potential resource leak",
+        ErrorNode);
+    R->markInteresting(LeakedHandle);
+    R->disablePathPruning();
+    C.emitReport(std::move(R));
+  }
+}
+
+void MagentaHandleChecker::reportDoubleRelease(SymbolRef HandleSym,
+                                               const SourceRange &Range,
+                                               CheckerContext &C) const {
+  ExplodedNode *ErrNode = C.generateErrorNode();
+  if (!ErrNode)
+    return;
+
+  auto R = llvm::make_unique<BugReport>(
+      *DoubleReleaseBugType, "Releasing a previously released handle", ErrNode);
+  R->addRange(Range);
+  R->markInteresting(HandleSym);
+  C.emitReport(std::move(R));
+}
+
+void MagentaHandleChecker::reportUseAfterFree(SymbolRef HandleSym,
+                                              const SourceRange &Range,
+                                              CheckerContext &Ctx) const {
+  ExplodedNode *ErrNode = Ctx.generateErrorNode();
+  if (!ErrNode)
+    return;
+
+  auto R = llvm::make_unique<BugReport>(
+      *UseAfterFreeBugType, "Using a previously released handle", ErrNode);
+  R->addRange(Range);
+  R->markInteresting(HandleSym);
+  Ctx.emitReport(std::move(R));
+}
+
+void ento::registerMagentaHandleChecker(CheckerManager &mgr) {
+  mgr.registerChecker<MagentaHandleChecker>();
+}
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -45,6 +45,7 @@
   LocalizationChecker.cpp
   MacOSKeychainAPIChecker.cpp
   MacOSXAPIChecker.cpp
+  MagentaHandleChecker.cpp
   MallocChecker.cpp
   MallocOverflowSecurityChecker.cpp
   MallocSizeofChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -69,6 +69,7 @@
 def OSX : Package<"osx">;
 def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden;
 def OSXOptIn : Package<"osx">, InPackage<OptIn>;
+def Magenta : Package<"magenta">, InPackage<Alpha>;
 
 def Cocoa : Package<"cocoa">, InPackage<OSX>;
 def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden;
@@ -770,3 +771,15 @@
   DescFile<"UnixAPIChecker.cpp">;
 
 } // end optin.portability
+
+//===----------------------------------------------------------------------===//
+// Magenta Specified Checkers
+//===----------------------------------------------------------------------===//
+
+let ParentPackage = Magenta in {
+
+def MagentaHandleChecker : Checker<"MagentaHandleChecker">,
+  HelpText<"A Checker that detect leaks related to Magenta handles">,
+  DescFile<"MagentaHandleChecker.cpp">;
+
+} // end "magenta"
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to