#include "InterCheckerAPI.h"
#include "clang/Basic/CharInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
using namespace clang;
using namespace ento;
using namespace std::placeholders;
namespace {
struct AnyArgExpr {
    AnyArgExpr(const Expr *Expression, unsigned ArgumentIndex)
      : Expression{Expression}, ArgumentIndex{ArgumentIndex} {}
  const Expr *Expression;
  unsigned ArgumentIndex;
};
struct SourceArgExpr : AnyArgExpr {
  using AnyArgExpr::AnyArgExpr; };
struct DestinationArgExpr : AnyArgExpr {
  using AnyArgExpr::AnyArgExpr; };
struct SizeArgExpr : AnyArgExpr {
  using AnyArgExpr::AnyArgExpr; };
using ErrorMessage = SmallString<128>;
enum class AccessKind { write, read };
static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
                                             AccessKind Access) {
  ErrorMessage Message;
  llvm::raw_svector_ostream Os(Message);
    Os << toUppercase(FunctionDescription.front())
     << &FunctionDescription.data()[1];
  if (Access == AccessKind::write) {
    Os << " overflows the destination buffer";
  } else {     Os << " accesses out-of-bound array element";
  }
  return Message;
}
enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
class CStringChecker : public Checker< eval::Call,
                                         check::PreStmt<DeclStmt>,
                                         check::LiveSymbols,
                                         check::DeadSymbols,
                                         check::RegionChanges
                                         > {
  mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
      BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
  mutable const char *CurrentFunctionDescription;
public:
      struct CStringChecksFilter {
    bool CheckCStringNullArg = false;
    bool CheckCStringOutOfBounds = false;
    bool CheckCStringBufferOverlap = false;
    bool CheckCStringNotNullTerm = false;
    bool CheckCStringUninitializedRead = false;
    CheckerNameRef CheckNameCStringNullArg;
    CheckerNameRef CheckNameCStringOutOfBounds;
    CheckerNameRef CheckNameCStringBufferOverlap;
    CheckerNameRef CheckNameCStringNotNullTerm;
    CheckerNameRef CheckNameCStringUninitializedRead;
  };
  CStringChecksFilter Filter;
  static void *getTag() { static int tag; return &tag; }
  bool evalCall(const CallEvent &Call, CheckerContext &C) const;
  void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
  void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const;
  void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
  ProgramStateRef
    checkRegionChanges(ProgramStateRef state,
                       const InvalidatedSymbols *,
                       ArrayRef<const MemRegion *> ExplicitRegions,
                       ArrayRef<const MemRegion *> Regions,
                       const LocationContext *LCtx,
                       const CallEvent *Call) const;
  using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
                                     const CallExpr *)>;
  CallDescriptionMap<FnCheck> Callbacks = {
      {{CDF_MaybeBuiltin, "memcpy", 3},
       std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
      {{CDF_MaybeBuiltin, "wmemcpy", 3},
       std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
      {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
      {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
      {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
      {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset},
      {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset},
      {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy},
      {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy},
      {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy},
      {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy},
      {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat},
      {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
      {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
      {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
      {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
      {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
      {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
      {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
      {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
      {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
      {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp},
      {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep},
      {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy},
      {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp},
      {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero},
      {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero},
  };
    CallDescription StdCopy{{"std", "copy"}, 3},
      StdCopyBackward{{"std", "copy_backward"}, 3};
  FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
  void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
  void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
  void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
  void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
  void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
                      ProgramStateRef state, SizeArgExpr Size,
                      DestinationArgExpr Dest, SourceArgExpr Source,
                      bool Restricted, bool IsMempcpy, bool IsWide) const;
  void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
  void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
  void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
  void evalstrLengthCommon(CheckerContext &C,
                           const CallExpr *CE,
                           bool IsStrnlen = false) const;
  void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
  void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
  void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
  void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const;
  void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd,
                        bool IsBounded, ConcatFnKind appendK,
                        bool returnPtr = true) const;
  void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
  void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
  void evalStrlcat(CheckerContext &C, const CallExpr *CE) const;
  void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
  void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
  void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
  void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
  void evalStrcmpCommon(CheckerContext &C,
                        const CallExpr *CE,
                        bool IsBounded = false,
                        bool IgnoreCase = false) const;
  void evalStrsep(CheckerContext &C, const CallExpr *CE) const;
  void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
  void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
  void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
  void evalMemset(CheckerContext &C, const CallExpr *CE) const;
  void evalBzero(CheckerContext &C, const CallExpr *CE) const;
    std::pair<ProgramStateRef , ProgramStateRef >
  static assumeZero(CheckerContext &C,
                    ProgramStateRef state, SVal V, QualType Ty);
  static ProgramStateRef setCStringLength(ProgramStateRef state,
                                              const MemRegion *MR,
                                              SVal strLength);
  static SVal getCStringLengthForRegion(CheckerContext &C,
                                        ProgramStateRef &state,
                                        const Expr *Ex,
                                        const MemRegion *MR,
                                        bool hypothetical);
  SVal getCStringLength(CheckerContext &C,
                        ProgramStateRef &state,
                        const Expr *Ex,
                        SVal Buf,
                        bool hypothetical = false) const;
  const StringLiteral *getCStringLiteral(CheckerContext &C,
                                         ProgramStateRef &state,
                                         const Expr *expr,
                                         SVal val) const;
  static ProgramStateRef InvalidateBuffer(CheckerContext &C,
                                          ProgramStateRef state,
                                          const Expr *Ex, SVal V,
                                          bool IsSourceBuffer,
                                          const Expr *Size);
  static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
                              const MemRegion *MR);
  static bool memsetAux(const Expr *DstBuffer, SVal CharE,
                        const Expr *Size, CheckerContext &C,
                        ProgramStateRef &State);
    ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State,
                               AnyArgExpr Arg, SVal l) const;
  ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
                                AnyArgExpr Buffer, SVal Element,
                                AccessKind Access, bool IsWide = false) const;
  ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
                                    AnyArgExpr Buffer, SizeArgExpr Size,
                                    AccessKind Access,
                                    bool IsWide = false) const;
  ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
                               SizeArgExpr Size, AnyArgExpr First,
                               AnyArgExpr Second, bool IsWide = false) const;
  void emitOverlapBug(CheckerContext &C,
                      ProgramStateRef state,
                      const Stmt *First,
                      const Stmt *Second) const;
  void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S,
                      StringRef WarningMsg) const;
  void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State,
                          const Stmt *S, StringRef WarningMsg) const;
  void emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
                         const Stmt *S, StringRef WarningMsg) const;
  void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const;
  void emitUninitializedReadBug(CheckerContext &C, ProgramStateRef State,
                             const Expr *E) const;
  ProgramStateRef checkAdditionOverflow(CheckerContext &C,
                                            ProgramStateRef state,
                                            NonLoc left,
                                            NonLoc right) const;
        static bool IsFirstBufInBound(CheckerContext &C,
                                ProgramStateRef state,
                                const Expr *FirstBuf,
                                const Expr *Size);
};
} 
REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
                           QualType Ty) {
  Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
  if (!val)
    return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
  SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
  return state->assume(svalBuilder.evalEQ(state, *val, zero));
}
ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
                                             ProgramStateRef State,
                                             AnyArgExpr Arg, SVal l) const {
    if (!State)
    return nullptr;
  ProgramStateRef stateNull, stateNonNull;
  std::tie(stateNull, stateNonNull) =
      assumeZero(C, State, l, Arg.Expression->getType());
  if (stateNull && !stateNonNull) {
    if (Filter.CheckCStringNullArg) {
      SmallString<80> buf;
      llvm::raw_svector_ostream OS(buf);
      assert(CurrentFunctionDescription);
      OS << "Null pointer passed as " << (Arg.ArgumentIndex + 1)
         << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) << " argument to "
         << CurrentFunctionDescription;
      emitNullArgBug(C, stateNull, Arg.Expression, OS.str());
    }
    return nullptr;
  }
    assert(stateNonNull);
  return stateNonNull;
}
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
                                              ProgramStateRef state,
                                              AnyArgExpr Buffer, SVal Element,
                                              AccessKind Access,
                                              bool IsWide) const {
    if (!state)
    return nullptr;
    const MemRegion *R = Element.getAsRegion();
  if (!R)
    return state;
  const auto *ER = dyn_cast<ElementRegion>(R);
  if (!ER)
    return state;
  SValBuilder &svalBuilder = C.getSValBuilder();
  ASTContext &Ctx = svalBuilder.getContext();
    NonLoc Idx = ER->getIndex();
  if (!IsWide) {
    if (ER->getValueType() != Ctx.CharTy)
      return state;
  } else {
    if (ER->getValueType() != Ctx.WideCharTy)
      return state;
    QualType SizeTy = Ctx.getSizeType();
    NonLoc WideSize =
        svalBuilder
            .makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
                        SizeTy)
            .castAs<NonLoc>();
    SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
    if (Offset.isUnknown())
      return state;
    Idx = Offset.castAs<NonLoc>();
  }
    const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
  DefinedOrUnknownSVal Size =
      getDynamicExtent(state, superReg, C.getSValBuilder());
  ProgramStateRef StInBound, StOutBound;
  std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
  if (StOutBound && !StInBound) {
                if (!Filter.CheckCStringOutOfBounds)
      return nullptr;
        ErrorMessage Message =
        createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
    emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message);
    return nullptr;
  }
    if (Access == AccessKind::read) {
    if (Filter.CheckCStringUninitializedRead &&
        StInBound->getSVal(ER).isUndef()) {
      emitUninitializedReadBug(C, StInBound, Buffer.Expression);
      return nullptr;
    }
  }
      return StInBound;
}
ProgramStateRef
CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
                                  AnyArgExpr Buffer, SizeArgExpr Size,
                                  AccessKind Access, bool IsWide) const {
    if (!State)
    return nullptr;
  SValBuilder &svalBuilder = C.getSValBuilder();
  ASTContext &Ctx = svalBuilder.getContext();
  QualType SizeTy = Size.Expression->getType();
  QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
    SVal BufVal = C.getSVal(Buffer.Expression);
  State = checkNonNull(C, State, Buffer, BufVal);
  if (!State)
    return nullptr;
    if (!Filter.CheckCStringOutOfBounds)
    return State;
        SVal LengthVal = C.getSVal(Size.Expression);
  Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
  if (!Length)
    return State;
    NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>();
  SVal Offset = svalBuilder.evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
  if (Offset.isUnknown())
    return nullptr;
  NonLoc LastOffset = Offset.castAs<NonLoc>();
    SVal BufStart =
      svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
  if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
    SVal BufEnd =
        svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
    State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
        if (!State)
      return nullptr;
  }
    return State;
}
ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
                                             ProgramStateRef state,
                                             SizeArgExpr Size, AnyArgExpr First,
                                             AnyArgExpr Second,
                                             bool IsWide) const {
  if (!Filter.CheckCStringBufferOverlap)
    return state;
      
    if (!state)
    return nullptr;
  ProgramStateRef stateTrue, stateFalse;
    if (First.Expression->getType()->getPointeeType().getAddressSpace() !=
      Second.Expression->getType()->getPointeeType().getAddressSpace())
    return state;
    const LocationContext *LCtx = C.getLocationContext();
  SVal firstVal = state->getSVal(First.Expression, LCtx);
  SVal secondVal = state->getSVal(Second.Expression, LCtx);
  Optional<Loc> firstLoc = firstVal.getAs<Loc>();
  if (!firstLoc)
    return state;
  Optional<Loc> secondLoc = secondVal.getAs<Loc>();
  if (!secondLoc)
    return state;
    SValBuilder &svalBuilder = C.getSValBuilder();
  std::tie(stateTrue, stateFalse) =
      state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
  if (stateTrue && !stateFalse) {
        emitOverlapBug(C, stateTrue, First.Expression, Second.Expression);
    return nullptr;
  }
    assert(stateFalse);
  state = stateFalse;
    QualType cmpTy = svalBuilder.getConditionType();
  SVal reverse =
      svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
  Optional<DefinedOrUnknownSVal> reverseTest =
      reverse.getAs<DefinedOrUnknownSVal>();
  if (!reverseTest)
    return state;
  std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
  if (stateTrue) {
    if (stateFalse) {
            return state;
    } else {
            std::swap(firstLoc, secondLoc);
            std::swap(First, Second);
    }
  }
    SVal LengthVal = state->getSVal(Size.Expression, LCtx);
  Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
  if (!Length)
    return state;
      ASTContext &Ctx = svalBuilder.getContext();
  QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
  SVal FirstStart =
      svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
  Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
  if (!FirstStartLoc)
    return state;
    SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc,
                                          *Length, CharPtrTy);
  Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
  if (!FirstEndLoc)
    return state;
    SVal Overlap =
      svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
  Optional<DefinedOrUnknownSVal> OverlapTest =
      Overlap.getAs<DefinedOrUnknownSVal>();
  if (!OverlapTest)
    return state;
  std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
  if (stateTrue && !stateFalse) {
        emitOverlapBug(C, stateTrue, First.Expression, Second.Expression);
    return nullptr;
  }
    assert(stateFalse);
  return stateFalse;
}
void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
                                  const Stmt *First, const Stmt *Second) const {
  ExplodedNode *N = C.generateErrorNode(state);
  if (!N)
    return;
  if (!BT_Overlap)
    BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap,
                                 categories::UnixAPI, "Improper arguments"));
    auto report = std::make_unique<PathSensitiveBugReport>(
      *BT_Overlap, "Arguments must not be overlapping buffers", N);
  report->addRange(First->getSourceRange());
  report->addRange(Second->getSourceRange());
  C.emitReport(std::move(report));
}
void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
                                    const Stmt *S, StringRef WarningMsg) const {
  if (ExplodedNode *N = C.generateErrorNode(State)) {
    if (!BT_Null)
      BT_Null.reset(new BuiltinBug(
          Filter.CheckNameCStringNullArg, categories::UnixAPI,
          "Null pointer argument in call to byte string function"));
    BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get());
    auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
    Report->addRange(S->getSourceRange());
    if (const auto *Ex = dyn_cast<Expr>(S))
      bugreporter::trackExpressionValue(N, Ex, *Report);
    C.emitReport(std::move(Report));
  }
}
void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
                                              ProgramStateRef State,
                                              const Expr *E) const {
  if (ExplodedNode *N = C.generateErrorNode(State)) {
    const char *Msg =
        "Bytes string function accesses uninitialized/garbage values";
    if (!BT_UninitRead)
      BT_UninitRead.reset(
          new BuiltinBug(Filter.CheckNameCStringUninitializedRead,
                         "Accessing unitialized/garbage values", Msg));
    BuiltinBug *BT = static_cast<BuiltinBug *>(BT_UninitRead.get());
    auto Report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
    Report->addRange(E->getSourceRange());
    bugreporter::trackExpressionValue(N, E, *Report);
    C.emitReport(std::move(Report));
  }
}
void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
                                        ProgramStateRef State, const Stmt *S,
                                        StringRef WarningMsg) const {
  if (ExplodedNode *N = C.generateErrorNode(State)) {
    if (!BT_Bounds)
      BT_Bounds.reset(new BuiltinBug(
          Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds
                                         : Filter.CheckNameCStringNullArg,
          "Out-of-bound array access",
          "Byte string function accesses out-of-bound array element"));
    BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get());
                auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
    Report->addRange(S->getSourceRange());
    C.emitReport(std::move(Report));
  }
}
void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
                                       const Stmt *S,
                                       StringRef WarningMsg) const {
  if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
    if (!BT_NotCString)
      BT_NotCString.reset(new BuiltinBug(
          Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
          "Argument is not a null-terminated string."));
    auto Report =
        std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
    Report->addRange(S->getSourceRange());
    C.emitReport(std::move(Report));
  }
}
void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
                                             ProgramStateRef State) const {
  if (ExplodedNode *N = C.generateErrorNode(State)) {
    if (!BT_AdditionOverflow)
      BT_AdditionOverflow.reset(
          new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API",
                         "Sum of expressions causes overflow."));
                const char *WarningMsg =
        "This expression will create a string whose length is too big to "
        "be represented as a size_t";
    auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
                                                           WarningMsg, N);
    C.emitReport(std::move(Report));
  }
}
ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
                                                     ProgramStateRef state,
                                                     NonLoc left,
                                                     NonLoc right) const {
    if (!Filter.CheckCStringOutOfBounds)
    return state;
    if (!state)
    return nullptr;
  SValBuilder &svalBuilder = C.getSValBuilder();
  BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
  QualType sizeTy = svalBuilder.getContext().getSizeType();
  const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
  NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
  SVal maxMinusRight;
  if (isa<nonloc::ConcreteInt>(right)) {
    maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
                                                 sizeTy);
  } else {
            maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
                                            sizeTy);
    left = right;
  }
  if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
    QualType cmpTy = svalBuilder.getConditionType();
        SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
                                                *maxMinusRightNL, cmpTy);
    ProgramStateRef stateOverflow, stateOkay;
    std::tie(stateOverflow, stateOkay) =
      state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
    if (stateOverflow && !stateOkay) {
            emitAdditionOverflowBug(C, stateOverflow);
      return nullptr;
    }
        assert(stateOkay);
    state = stateOkay;
  }
  return state;
}
ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state,
                                                const MemRegion *MR,
                                                SVal strLength) {
  assert(!strLength.isUndef() && "Attempt to set an undefined string length");
  MR = MR->StripCasts();
  switch (MR->getKind()) {
  case MemRegion::StringRegionKind:
            return state;
  case MemRegion::SymbolicRegionKind:
  case MemRegion::AllocaRegionKind:
  case MemRegion::NonParamVarRegionKind:
  case MemRegion::ParamVarRegionKind:
  case MemRegion::FieldRegionKind:
  case MemRegion::ObjCIvarRegionKind:
        break;
  case MemRegion::ElementRegionKind:
            return state;
  default:
                    return state;
  }
  if (strLength.isUnknown())
    return state->remove<CStringLength>(MR);
  return state->set<CStringLength>(MR, strLength);
}
SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
                                               ProgramStateRef &state,
                                               const Expr *Ex,
                                               const MemRegion *MR,
                                               bool hypothetical) {
  if (!hypothetical) {
        const SVal *Recorded = state->get<CStringLength>(MR);
    if (Recorded)
      return *Recorded;
  }
    SValBuilder &svalBuilder = C.getSValBuilder();
  QualType sizeTy = svalBuilder.getContext().getSizeType();
  SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
                                                    MR, Ex, sizeTy,
                                                    C.getLocationContext(),
                                                    C.blockCount());
  if (!hypothetical) {
    if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
            BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
      const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
      llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
      const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
                                                        fourInt);
      NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
      SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn,
                                                maxLength, sizeTy);
      state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true);
    }
    state = state->set<CStringLength>(MR, strLength);
  }
  return strLength;
}
SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
                                      const Expr *Ex, SVal Buf,
                                      bool hypothetical) const {
  const MemRegion *MR = Buf.getAsRegion();
  if (!MR) {
                if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
      if (Filter.CheckCStringNotNullTerm) {
        SmallString<120> buf;
        llvm::raw_svector_ostream os(buf);
        assert(CurrentFunctionDescription);
        os << "Argument to " << CurrentFunctionDescription
           << " is the address of the label '" << Label->getLabel()->getName()
           << "', which is not a null-terminated string";
        emitNotCStringBug(C, state, Ex, os.str());
      }
      return UndefinedVal();
    }
        return UnknownVal();
  }
      MR = MR->StripCasts();
  switch (MR->getKind()) {
  case MemRegion::StringRegionKind: {
            SValBuilder &svalBuilder = C.getSValBuilder();
    QualType sizeTy = svalBuilder.getContext().getSizeType();
    const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
    return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
  }
  case MemRegion::SymbolicRegionKind:
  case MemRegion::AllocaRegionKind:
  case MemRegion::NonParamVarRegionKind:
  case MemRegion::ParamVarRegionKind:
  case MemRegion::FieldRegionKind:
  case MemRegion::ObjCIvarRegionKind:
    return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
  case MemRegion::CompoundLiteralRegionKind:
        return UnknownVal();
  case MemRegion::ElementRegionKind:
            return UnknownVal();
  default:
                if (Filter.CheckCStringNotNullTerm) {
      SmallString<120> buf;
      llvm::raw_svector_ostream os(buf);
      assert(CurrentFunctionDescription);
      os << "Argument to " << CurrentFunctionDescription << " is ";
      if (SummarizeRegion(os, C.getASTContext(), MR))
        os << ", which is not a null-terminated string";
      else
        os << "not a null-terminated string";
      emitNotCStringBug(C, state, Ex, os.str());
    }
    return UndefinedVal();
  }
}
const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
  ProgramStateRef &state, const Expr *expr, SVal val) const {
    const MemRegion *bufRegion = val.getAsRegion();
  if (!bufRegion)
    return nullptr;
    bufRegion = bufRegion->StripCasts();
    const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
  if (!strRegion)
    return nullptr;
    return strRegion->getStringLiteral();
}
bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
                                       ProgramStateRef state,
                                       const Expr *FirstBuf,
                                       const Expr *Size) {
      
    SValBuilder &svalBuilder = C.getSValBuilder();
  ASTContext &Ctx = svalBuilder.getContext();
  const LocationContext *LCtx = C.getLocationContext();
  QualType sizeTy = Size->getType();
  QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
  SVal BufVal = state->getSVal(FirstBuf, LCtx);
  SVal LengthVal = state->getSVal(Size, LCtx);
  Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
  if (!Length)
    return true; 
    NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
  SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy);
  if (Offset.isUnknown())
    return true;   NonLoc LastOffset = Offset.castAs<NonLoc>();
    SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
  Optional<Loc> BufLoc = BufStart.getAs<Loc>();
  if (!BufLoc)
    return true; 
  SVal BufEnd =
      svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy);
    const MemRegion *R = BufEnd.getAsRegion();
  if (!R)
    return true; 
  const ElementRegion *ER = dyn_cast<ElementRegion>(R);
  if (!ER)
    return true; 
      assert(ER->getValueType() == C.getASTContext().CharTy &&
         "IsFirstBufInBound should only be called with char* ElementRegions");
    const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
  DefinedOrUnknownSVal SizeDV = getDynamicExtent(state, superReg, svalBuilder);
    DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
  ProgramStateRef StInBound = state->assumeInBound(Idx, SizeDV, true);
  return static_cast<bool>(StInBound);
}
ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
                                                 ProgramStateRef state,
                                                 const Expr *E, SVal V,
                                                 bool IsSourceBuffer,
                                                 const Expr *Size) {
  Optional<Loc> L = V.getAs<Loc>();
  if (!L)
    return state;
        if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
    const MemRegion *R = MR->getRegion()->StripCasts();
            if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
      R = ER->getSuperRegion();
          }
        const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
    bool CausesPointerEscape = false;
    RegionAndSymbolInvalidationTraits ITraits;
            if (IsSourceBuffer) {
      ITraits.setTrait(R->getBaseRegion(),
                       RegionAndSymbolInvalidationTraits::TK_PreserveContents);
      ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
      CausesPointerEscape = true;
    } else {
      const MemRegion::Kind& K = R->getKind();
      if (K == MemRegion::FieldRegionKind)
        if (Size && IsFirstBufInBound(C, state, E, Size)) {
                              ITraits.setTrait(
              R,
              RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
        }
    }
    return state->invalidateRegions(R, E, C.blockCount(), LCtx,
                                    CausesPointerEscape, nullptr, nullptr,
                                    &ITraits);
  }
        return state->killBinding(*L);
}
bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
                                     const MemRegion *MR) {
  switch (MR->getKind()) {
  case MemRegion::FunctionCodeRegionKind: {
    if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
      os << "the address of the function '" << *FD << '\'';
    else
      os << "the address of a function";
    return true;
  }
  case MemRegion::BlockCodeRegionKind:
    os << "block text";
    return true;
  case MemRegion::BlockDataRegionKind:
    os << "a block";
    return true;
  case MemRegion::CXXThisRegionKind:
  case MemRegion::CXXTempObjectRegionKind:
    os << "a C++ temp object of type "
       << cast<TypedValueRegion>(MR)->getValueType();
    return true;
  case MemRegion::NonParamVarRegionKind:
    os << "a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
    return true;
  case MemRegion::ParamVarRegionKind:
    os << "a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
    return true;
  case MemRegion::FieldRegionKind:
    os << "a field of type " << cast<TypedValueRegion>(MR)->getValueType();
    return true;
  case MemRegion::ObjCIvarRegionKind:
    os << "an instance variable of type "
       << cast<TypedValueRegion>(MR)->getValueType();
    return true;
  default:
    return false;
  }
}
bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
                               const Expr *Size, CheckerContext &C,
                               ProgramStateRef &State) {
  SVal MemVal = C.getSVal(DstBuffer);
  SVal SizeVal = C.getSVal(Size);
  const MemRegion *MR = MemVal.getAsRegion();
  if (!MR)
    return false;
          RegionOffset Offset = MR->getAsOffset();
  const MemRegion *BR = Offset.getRegion();
  Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
  if (!SizeNL)
    return false;
  SValBuilder &svalBuilder = C.getSValBuilder();
  ASTContext &Ctx = C.getASTContext();
      if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
      Offset.getOffset() == 0) {
        DefinedOrUnknownSVal SizeDV = getDynamicExtent(State, BR, svalBuilder);
    ProgramStateRef StateWholeReg, StateNotWholeReg;
    std::tie(StateWholeReg, StateNotWholeReg) =
        State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL));
            CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy);
    ProgramStateRef StateNullChar, StateNonNullChar;
    std::tie(StateNullChar, StateNonNullChar) =
        assumeZero(C, State, CharVal, Ctx.UnsignedCharTy);
    if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
        !StateNonNullChar) {
                                          State = State->bindDefaultZero(svalBuilder.makeLoc(BR),
                                     C.getLocationContext());
    } else {
                  State = InvalidateBuffer(C, State, DstBuffer, MemVal,
                                false, Size);
    }
    if (StateNullChar && !StateNonNullChar) {
                  State = setCStringLength(State, MR,
                               svalBuilder.makeZeroVal(Ctx.getSizeType()));
    } else if (!StateNullChar && StateNonNullChar) {
      SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
          CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(),
          C.getLocationContext(), C.blockCount());
                  SVal NewStrLenGESize = svalBuilder.evalBinOp(
          State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType());
      State = setCStringLength(
          State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true),
          MR, NewStrLen);
    }
  } else {
            State = InvalidateBuffer(C, State, DstBuffer, MemVal,
                              false, Size);
  }
  return true;
}
void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
                                    ProgramStateRef state, SizeArgExpr Size,
                                    DestinationArgExpr Dest,
                                    SourceArgExpr Source, bool Restricted,
                                    bool IsMempcpy, bool IsWide) const {
  CurrentFunctionDescription = "memory copy function";
    const LocationContext *LCtx = C.getLocationContext();
  SVal sizeVal = state->getSVal(Size.Expression, LCtx);
  QualType sizeTy = Size.Expression->getType();
  ProgramStateRef stateZeroSize, stateNonZeroSize;
  std::tie(stateZeroSize, stateNonZeroSize) =
      assumeZero(C, state, sizeVal, sizeTy);
    SVal destVal = state->getSVal(Dest.Expression, LCtx);
      if (stateZeroSize && !stateNonZeroSize) {
    stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
    C.addTransition(stateZeroSize);
    return;
  }
    if (stateNonZeroSize) {
    state = stateNonZeroSize;
            state = checkNonNull(C, state, Dest, destVal);
    if (!state)
      return;
        SVal srcVal = state->getSVal(Source.Expression, LCtx);
            state = checkNonNull(C, state, Source, srcVal);
    if (!state)
      return;
        state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
    state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
    if (Restricted)
      state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
    if (!state)
      return;
            if (IsMempcpy) {
            SValBuilder &SvalBuilder = C.getSValBuilder();
      ASTContext &Ctx = SvalBuilder.getContext();
      QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
      SVal DestRegCharVal =
          SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
      SVal lastElement = C.getSValBuilder().evalBinOp(
          state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
                  if (lastElement.isUnknown())
        lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
                                                          C.blockCount());
            state = state->BindExpr(CE, LCtx, lastElement);
    } else {
                  state = state->BindExpr(CE, LCtx, destVal);
    }
                            state =
        InvalidateBuffer(C, state, Dest.Expression, C.getSVal(Dest.Expression),
                          false, Size.Expression);
            state = InvalidateBuffer(C, state, Source.Expression,
                             C.getSVal(Source.Expression),
                              true, nullptr);
    C.addTransition(state);
  }
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
                                bool IsWide) const {
      DestinationArgExpr Dest = {CE->getArg(0), 0};
  SourceArgExpr Src = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  ProgramStateRef State = C.getState();
  constexpr bool IsRestricted = true;
  constexpr bool IsMempcpy = false;
  evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
                 IsWide);
}
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
      DestinationArgExpr Dest = {CE->getArg(0), 0};
  SourceArgExpr Src = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  constexpr bool IsRestricted = true;
  constexpr bool IsMempcpy = true;
  evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
                 false);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
      DestinationArgExpr Dest = {CE->getArg(0), 0};
  SourceArgExpr Src = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  constexpr bool IsRestricted = false;
  constexpr bool IsMempcpy = false;
  evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
                 false);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
    SourceArgExpr Src(CE->getArg(0), 0);
  DestinationArgExpr Dest = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  constexpr bool IsRestricted = false;
  constexpr bool IsMempcpy = false;
  evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
                 false);
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
    CurrentFunctionDescription = "memory comparison function";
  AnyArgExpr Left = {CE->getArg(0), 0};
  AnyArgExpr Right = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  ProgramStateRef State = C.getState();
  SValBuilder &Builder = C.getSValBuilder();
  const LocationContext *LCtx = C.getLocationContext();
    SVal sizeVal = State->getSVal(Size.Expression, LCtx);
  QualType sizeTy = Size.Expression->getType();
  ProgramStateRef stateZeroSize, stateNonZeroSize;
  std::tie(stateZeroSize, stateNonZeroSize) =
      assumeZero(C, State, sizeVal, sizeTy);
      if (stateZeroSize) {
    State = stateZeroSize;
    State = State->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType()));
    C.addTransition(State);
  }
    if (stateNonZeroSize) {
    State = stateNonZeroSize;
                DefinedOrUnknownSVal LV =
        State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
    DefinedOrUnknownSVal RV =
        State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
        ProgramStateRef SameBuffer, NotSameBuffer;
    std::tie(SameBuffer, NotSameBuffer) =
        State->assume(Builder.evalEQ(State, LV, RV));
            if (SameBuffer && !NotSameBuffer) {
      State = SameBuffer;
      State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
      if (State) {
        State =
            SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType()));
        C.addTransition(State);
      }
      return;
    }
            assert(NotSameBuffer);
    State = CheckBufferAccess(C, State, Right, Size, AccessKind::read);
    State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
    if (State) {
            SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
      State = State->BindExpr(CE, LCtx, CmpV);
      C.addTransition(State);
    }
  }
}
void CStringChecker::evalstrLength(CheckerContext &C,
                                   const CallExpr *CE) const {
    evalstrLengthCommon(C, CE,  false);
}
void CStringChecker::evalstrnLength(CheckerContext &C,
                                    const CallExpr *CE) const {
    evalstrLengthCommon(C, CE,  true);
}
void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
                                         bool IsStrnlen) const {
  CurrentFunctionDescription = "string length function";
  ProgramStateRef state = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
  if (IsStrnlen) {
    const Expr *maxlenExpr = CE->getArg(1);
    SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
    ProgramStateRef stateZeroSize, stateNonZeroSize;
    std::tie(stateZeroSize, stateNonZeroSize) =
      assumeZero(C, state, maxlenVal, maxlenExpr->getType());
            if (stateZeroSize) {
      SVal zero = C.getSValBuilder().makeZeroVal(CE->getType());
      stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
      C.addTransition(stateZeroSize);
    }
        if (!stateNonZeroSize)
      return;
        state = stateNonZeroSize;
  }
    AnyArgExpr Arg = {CE->getArg(0), 0};
  SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
  state = checkNonNull(C, state, Arg, ArgVal);
  if (!state)
    return;
  SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal);
      if (strLength.isUndef())
    return;
  DefinedOrUnknownSVal result = UnknownVal();
      if (IsStrnlen) {
    QualType cmpTy = C.getSValBuilder().getConditionType();
            const Expr *maxlenExpr = CE->getArg(1);
    SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
    Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
    Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
    if (strLengthNL && maxlenValNL) {
      ProgramStateRef stateStringTooLong, stateStringNotTooLong;
            std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
          C.getSValBuilder()
              .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
              .castAs<DefinedOrUnknownSVal>());
      if (stateStringTooLong && !stateStringNotTooLong) {
                result = *maxlenValNL;
      } else if (stateStringNotTooLong && !stateStringTooLong) {
                result = *strLengthNL;
      }
    }
    if (result.isUnknown()) {
                              result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
                                                   C.blockCount());
      NonLoc resultNL = result.castAs<NonLoc>();
      if (strLengthNL) {
        state = state->assume(C.getSValBuilder().evalBinOpNN(
                                  state, BO_LE, resultNL, *strLengthNL, cmpTy)
                                  .castAs<DefinedOrUnknownSVal>(), true);
      }
      if (maxlenValNL) {
        state = state->assume(C.getSValBuilder().evalBinOpNN(
                                  state, BO_LE, resultNL, *maxlenValNL, cmpTy)
                                  .castAs<DefinedOrUnknownSVal>(), true);
      }
    }
  } else {
        result = strLength.castAs<DefinedOrUnknownSVal>();
            if (result.isUnknown()) {
      result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
                                                   C.blockCount());
    }
  }
    assert(!result.isUnknown() && "Should have conjured a value by now");
  state = state->BindExpr(CE, LCtx, result);
  C.addTransition(state);
}
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    false,
                    false,
                    ConcatFnKind::none);
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    false,
                    true,
                    ConcatFnKind::none);
}
void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    true,
                    false,
                    ConcatFnKind::none);
}
void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    true,
                    true,
                    ConcatFnKind::none,
                    false);
}
void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    false,
                    false,
                    ConcatFnKind::strcat);
}
void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
    evalStrcpyCommon(C, CE,
                    false,
                    true,
                    ConcatFnKind::strcat);
}
void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const {
        evalStrcpyCommon(C, CE,
                    false,
                    true,
                    ConcatFnKind::strlcat,
                    false);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
                                      bool ReturnEnd, bool IsBounded,
                                      ConcatFnKind appendK,
                                      bool returnPtr) const {
  if (appendK == ConcatFnKind::none)
    CurrentFunctionDescription = "string copy function";
  else
    CurrentFunctionDescription = "string concatenation function";
  ProgramStateRef state = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
    DestinationArgExpr Dst = {CE->getArg(0), 0};
  SVal DstVal = state->getSVal(Dst.Expression, LCtx);
  state = checkNonNull(C, state, Dst, DstVal);
  if (!state)
    return;
    SourceArgExpr srcExpr = {CE->getArg(1), 1};
  SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
  state = checkNonNull(C, state, srcExpr, srcVal);
  if (!state)
    return;
    SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal);
  Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
    SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal);
  Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
    if (strLength.isUndef())
    return;
  SValBuilder &svalBuilder = C.getSValBuilder();
  QualType cmpTy = svalBuilder.getConditionType();
  QualType sizeTy = svalBuilder.getContext().getSizeType();
        SVal amountCopied = UnknownVal();
  SVal maxLastElementIndex = UnknownVal();
  const char *boundWarning = nullptr;
      SizeArgExpr SrcExprAsSizeDummy = {srcExpr.Expression, srcExpr.ArgumentIndex};
  state = CheckOverlap(
      C, state,
      (IsBounded ? SizeArgExpr{CE->getArg(2), 2} : SrcExprAsSizeDummy), Dst,
      srcExpr);
  if (!state)
    return;
    if (IsBounded) {
        SizeArgExpr lenExpr = {CE->getArg(2), 2};
    SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
        lenVal =
        svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
    Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
            if (strLengthNL && lenValNL) {
      switch (appendK) {
      case ConcatFnKind::none:
      case ConcatFnKind::strcat: {
        ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
                                std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
            svalBuilder
                .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
                .castAs<DefinedOrUnknownSVal>());
        if (stateSourceTooLong && !stateSourceNotTooLong) {
                              state = stateSourceTooLong;
          amountCopied = lenVal;
        } else if (!stateSourceTooLong && stateSourceNotTooLong) {
                    state = stateSourceNotTooLong;
          amountCopied = strLength;
        }
        break;
      }
      case ConcatFnKind::strlcat:
        if (!dstStrLengthNL)
          return;
                SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
                                                 *dstStrLengthNL, sizeTy);
        if (!isa<NonLoc>(freeSpace))
          return;
        freeSpace =
            svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
                                  svalBuilder.makeIntVal(1, sizeTy), sizeTy);
        Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
                        if (!freeSpaceNL)
          return;
        SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
            state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
        ProgramStateRef TrueState, FalseState;
        std::tie(TrueState, FalseState) =
            state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
                if (TrueState && !FalseState) {
          amountCopied = strLength;
        }
                if (!TrueState && FalseState) {
          amountCopied = freeSpace;
        }
        if (TrueState && FalseState)
          amountCopied = UnknownVal();
        break;
      }
    }
        if (lenValNL) {
      switch (appendK) {
      case ConcatFnKind::strcat:
        
                                if (dstStrLength.isUndef())
          return;
        if (dstStrLengthNL) {
          maxLastElementIndex = svalBuilder.evalBinOpNN(
              state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
          boundWarning = "Size argument is greater than the free space in the "
                         "destination buffer";
        }
        break;
      case ConcatFnKind::none:
      case ConcatFnKind::strlcat:
                                
                                ProgramStateRef StateZeroSize, StateNonZeroSize;
        std::tie(StateZeroSize, StateNonZeroSize) =
            assumeZero(C, state, *lenValNL, sizeTy);
                if (StateZeroSize && !StateNonZeroSize) {
          if (returnPtr) {
            StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
          } else {
            if (appendK == ConcatFnKind::none) {
                            StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength);
            } else {
                            SVal retSize = svalBuilder.evalBinOp(
                  state, BO_Add, strLength, dstStrLength, sizeTy);
              StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize);
            }
          }
          C.addTransition(StateZeroSize);
          return;
        }
                                NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
        maxLastElementIndex =
            svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
        boundWarning = "Size argument is greater than the length of the "
                       "destination buffer";
        break;
      }
    }
  } else {
            amountCopied = strLength;
  }
  assert(state);
        SVal finalStrLength = UnknownVal();
  SVal strlRetVal = UnknownVal();
  if (appendK == ConcatFnKind::none && !returnPtr) {
        strlRetVal = strLength;
  }
        if (appendK != ConcatFnKind::none) {
            if (dstStrLength.isUndef())
      return;
    if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
      strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL,
                                           *dstStrLengthNL, sizeTy);
    }
    Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
        if (amountCopiedNL && dstStrLengthNL) {
            state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL);
      if (!state)
        return;
      finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL,
                                               *dstStrLengthNL, sizeTy);
    }
            if (finalStrLength.isUnknown()) {
                  finalStrLength = getCStringLength(C, state, CE, DstVal, true);
      assert(!finalStrLength.isUndef());
      if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
        if (amountCopiedNL && appendK == ConcatFnKind::none) {
                              SVal sourceInResult = svalBuilder.evalBinOpNN(
              state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
          state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
                                true);
          if (!state)
            return;
        }
        if (dstStrLengthNL && appendK != ConcatFnKind::none) {
                              SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
                                                      *finalStrLengthNL,
                                                      *dstStrLengthNL,
                                                      cmpTy);
          state =
              state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true);
          if (!state)
            return;
        }
      }
    }
  } else {
            finalStrLength = amountCopied;
  }
  SVal Result;
  if (returnPtr) {
            Result = (ReturnEnd ? UnknownVal() : DstVal);
  } else {
    if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
            Result = strlRetVal;
    else
      Result = finalStrLength;
  }
  assert(state);
      if (Optional<loc::MemRegionVal> dstRegVal =
      DstVal.getAs<loc::MemRegionVal>()) {
    QualType ptrTy = Dst.Expression->getType();
            if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
      SVal maxLastElement =
          svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
      state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write);
      if (!state)
        return;
    }
        if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
      SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
          *knownStrLength, ptrTy);
            if (!boundWarning) {
        state = CheckLocation(C, state, Dst, lastElement, AccessKind::write);
        if (!state)
          return;
      }
            if (returnPtr && ReturnEnd)
        Result = lastElement;
    }
                                state = InvalidateBuffer(C, state, Dst.Expression, *dstRegVal,
                              false, nullptr);
            state = InvalidateBuffer(C, state, srcExpr.Expression, srcVal,
                              true, nullptr);
        if (IsBounded && (appendK == ConcatFnKind::none)) {
                              if (amountCopied != strLength)
        finalStrLength = UnknownVal();
    }
    state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
  }
  assert(state);
  if (returnPtr) {
            if (ReturnEnd && Result.isUnknown()) {
      Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
    }
  }
    state = state->BindExpr(CE, LCtx, Result);
  C.addTransition(state);
}
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
    evalStrcmpCommon(C, CE,  false,  false);
}
void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
    evalStrcmpCommon(C, CE,  true,  false);
}
void CStringChecker::evalStrcasecmp(CheckerContext &C,
    const CallExpr *CE) const {
    evalStrcmpCommon(C, CE,  false,  true);
}
void CStringChecker::evalStrncasecmp(CheckerContext &C,
    const CallExpr *CE) const {
    evalStrcmpCommon(C, CE,  true,  true);
}
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
    bool IsBounded, bool IgnoreCase) const {
  CurrentFunctionDescription = "string comparison function";
  ProgramStateRef state = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
    AnyArgExpr Left = {CE->getArg(0), 0};
  SVal LeftVal = state->getSVal(Left.Expression, LCtx);
  state = checkNonNull(C, state, Left, LeftVal);
  if (!state)
    return;
    AnyArgExpr Right = {CE->getArg(1), 1};
  SVal RightVal = state->getSVal(Right.Expression, LCtx);
  state = checkNonNull(C, state, Right, RightVal);
  if (!state)
    return;
    SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal);
  if (LeftLength.isUndef())
    return;
    SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal);
  if (RightLength.isUndef())
    return;
        DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>();
  DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>();
    SValBuilder &svalBuilder = C.getSValBuilder();
  DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
  ProgramStateRef StSameBuf, StNotSameBuf;
  std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
      if (StSameBuf) {
    StSameBuf = StSameBuf->BindExpr(CE, LCtx,
        svalBuilder.makeZeroVal(CE->getType()));
    C.addTransition(StSameBuf);
        if (!StNotSameBuf)
      return;
  }
  assert(StNotSameBuf);
  state = StNotSameBuf;
    
    const StringLiteral *LeftStrLiteral =
      getCStringLiteral(C, state, Left.Expression, LeftVal);
  const StringLiteral *RightStrLiteral =
      getCStringLiteral(C, state, Right.Expression, RightVal);
  bool canComputeResult = false;
  SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
      C.blockCount());
  if (LeftStrLiteral && RightStrLiteral) {
    StringRef LeftStrRef = LeftStrLiteral->getString();
    StringRef RightStrRef = RightStrLiteral->getString();
    if (IsBounded) {
            const Expr *lenExpr = CE->getArg(2);
      SVal lenVal = state->getSVal(lenExpr, LCtx);
            if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
                LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue());
        RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue());
        canComputeResult = true;
      }
    } else {
            canComputeResult = true;
    }
    if (canComputeResult) {
            size_t s1Term = LeftStrRef.find('\0');
      if (s1Term != StringRef::npos)
        LeftStrRef = LeftStrRef.substr(0, s1Term);
      size_t s2Term = RightStrRef.find('\0');
      if (s2Term != StringRef::npos)
        RightStrRef = RightStrRef.substr(0, s2Term);
            int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
                                  : LeftStrRef.compare(RightStrRef);
                  if (compareRes == 0) {
        resultVal = svalBuilder.makeIntVal(compareRes, CE->getType());
      }
      else {
        DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType());
                        BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT;
        SVal compareWithZero =
          svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
              svalBuilder.getConditionType());
        DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>();
        state = state->assume(compareWithZeroVal, true);
      }
    }
  }
  state = state->BindExpr(CE, LCtx, resultVal);
    C.addTransition(state);
}
void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
      SourceArgExpr SearchStrPtr = {CE->getArg(0), 0};
  QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
  if (CharPtrTy.isNull() ||
      CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType())
    return;
  CurrentFunctionDescription = "strsep()";
  ProgramStateRef State = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
      SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
  State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
  if (!State)
    return;
    AnyArgExpr DelimStr = {CE->getArg(1), 1};
  SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
  State = checkNonNull(C, State, DelimStr, DelimStrVal);
  if (!State)
    return;
  SValBuilder &SVB = C.getSValBuilder();
  SVal Result;
  if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
        Result = State->getSVal(*SearchStrLoc, CharPtrTy);
            State = InvalidateBuffer(C, State, SearchStrPtr.Expression, Result,
                              false, nullptr);
            State = State->bindLoc(*SearchStrLoc,
        SVB.conjureSymbolVal(getTag(),
          CE,
          LCtx,
          CharPtrTy,
          C.blockCount()),
        LCtx);
  } else {
    assert(SearchStrVal.isUnknown());
        Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
  }
    State = State->BindExpr(CE, LCtx, Result);
  C.addTransition(State);
}
void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const {
  evalStdCopyCommon(C, CE);
}
void CStringChecker::evalStdCopyBackward(CheckerContext &C,
    const CallExpr *CE) const {
  evalStdCopyCommon(C, CE);
}
void CStringChecker::evalStdCopyCommon(CheckerContext &C,
    const CallExpr *CE) const {
  if (!CE->getArg(2)->getType()->isPointerType())
    return;
  ProgramStateRef State = C.getState();
  const LocationContext *LCtx = C.getLocationContext();
        
    const Expr *Dst = CE->getArg(2);
  SVal DstVal = State->getSVal(Dst, LCtx);
  State = InvalidateBuffer(C, State, Dst, DstVal, false,
      nullptr);
  SValBuilder &SVB = C.getSValBuilder();
  SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
  State = State->BindExpr(CE, LCtx, ResultVal);
  C.addTransition(State);
}
void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
    CurrentFunctionDescription = "memory set function";
  DestinationArgExpr Buffer = {CE->getArg(0), 0};
  AnyArgExpr CharE = {CE->getArg(1), 1};
  SizeArgExpr Size = {CE->getArg(2), 2};
  ProgramStateRef State = C.getState();
    const LocationContext *LCtx = C.getLocationContext();
  SVal SizeVal = C.getSVal(Size.Expression);
  QualType SizeTy = Size.Expression->getType();
  ProgramStateRef ZeroSize, NonZeroSize;
  std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy);
    SVal BufferPtrVal = C.getSVal(Buffer.Expression);
      if (ZeroSize && !NonZeroSize) {
    ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal);
    C.addTransition(ZeroSize);
    return;
  }
      State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal);
  if (!State)
    return;
  State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
  if (!State)
    return;
        if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression),
                 Size.Expression, C, State))
    return;
  State = State->BindExpr(CE, LCtx, BufferPtrVal);
  C.addTransition(State);
}
void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
  CurrentFunctionDescription = "memory clearance function";
  DestinationArgExpr Buffer = {CE->getArg(0), 0};
  SizeArgExpr Size = {CE->getArg(1), 1};
  SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
  ProgramStateRef State = C.getState();
    SVal SizeVal = C.getSVal(Size.Expression);
  QualType SizeTy = Size.Expression->getType();
  ProgramStateRef StateZeroSize, StateNonZeroSize;
  std::tie(StateZeroSize, StateNonZeroSize) =
    assumeZero(C, State, SizeVal, SizeTy);
      if (StateZeroSize && !StateNonZeroSize) {
    C.addTransition(StateZeroSize);
    return;
  }
    SVal MemVal = C.getSVal(Buffer.Expression);
      State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal);
  if (!State)
    return;
  State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
  if (!State)
    return;
  if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State))
    return;
  C.addTransition(State);
}
CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call,
                                                     CheckerContext &C) const {
  const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
  if (!CE)
    return nullptr;
  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
  if (!FD)
    return nullptr;
  if (StdCopy.matches(Call))
    return &CStringChecker::evalStdCopy;
  if (StdCopyBackward.matches(Call))
    return &CStringChecker::evalStdCopyBackward;
          for (auto I : CE->arguments()) {
    QualType T = I->getType();
    if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
      return nullptr;
  }
  const FnCheck *Callback = Callbacks.lookup(Call);
  if (Callback)
    return *Callback;
  return nullptr;
}
bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
  FnCheck Callback = identifyCall(Call, C);
    if (!Callback)
    return false;
    const auto *CE = cast<CallExpr>(Call.getOriginExpr());
  Callback(this, C, CE);
              return C.isDifferent();
}
void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
    ProgramStateRef state = C.getState();
  for (const auto *I : DS->decls()) {
    const VarDecl *D = dyn_cast<VarDecl>(I);
    if (!D)
      continue;
        if (!D->getType()->isArrayType())
      continue;
    const Expr *Init = D->getInit();
    if (!Init)
      continue;
    if (!isa<StringLiteral>(Init))
      continue;
    Loc VarLoc = state->getLValue(D, C.getLocationContext());
    const MemRegion *MR = VarLoc.getAsRegion();
    if (!MR)
      continue;
    SVal StrVal = C.getSVal(Init);
    assert(StrVal.isValid() && "Initializer string is unknown or undefined");
    DefinedOrUnknownSVal strLength =
      getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
    state = state->set<CStringLength>(MR, strLength);
  }
  C.addTransition(state);
}
ProgramStateRef
CStringChecker::checkRegionChanges(ProgramStateRef state,
    const InvalidatedSymbols *,
    ArrayRef<const MemRegion *> ExplicitRegions,
    ArrayRef<const MemRegion *> Regions,
    const LocationContext *LCtx,
    const CallEvent *Call) const {
  CStringLengthTy Entries = state->get<CStringLength>();
  if (Entries.isEmpty())
    return state;
  llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
  llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
    for (ArrayRef<const MemRegion *>::iterator
      I = Regions.begin(), E = Regions.end(); I != E; ++I) {
    const MemRegion *MR = *I;
    Invalidated.insert(MR);
    SuperRegions.insert(MR);
    while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
      MR = SR->getSuperRegion();
      SuperRegions.insert(MR);
    }
  }
  CStringLengthTy::Factory &F = state->get_context<CStringLength>();
    for (CStringLengthTy::iterator I = Entries.begin(),
      E = Entries.end(); I != E; ++I) {
    const MemRegion *MR = I.getKey();
        if (SuperRegions.count(MR)) {
      Entries = F.remove(Entries, MR);
      continue;
    }
        const MemRegion *Super = MR;
    while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
      Super = SR->getSuperRegion();
      if (Invalidated.count(Super)) {
        Entries = F.remove(Entries, MR);
        break;
      }
    }
  }
  return state->set<CStringLength>(Entries);
}
void CStringChecker::checkLiveSymbols(ProgramStateRef state,
    SymbolReaper &SR) const {
    CStringLengthTy Entries = state->get<CStringLength>();
  for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
      I != E; ++I) {
    SVal Len = I.getData();
    for (SymExpr::symbol_iterator si = Len.symbol_begin(),
        se = Len.symbol_end(); si != se; ++si)
      SR.markInUse(*si);
  }
}
void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
    CheckerContext &C) const {
  ProgramStateRef state = C.getState();
  CStringLengthTy Entries = state->get<CStringLength>();
  if (Entries.isEmpty())
    return;
  CStringLengthTy::Factory &F = state->get_context<CStringLength>();
  for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
      I != E; ++I) {
    SVal Len = I.getData();
    if (SymbolRef Sym = Len.getAsSymbol()) {
      if (SR.isDead(Sym))
        Entries = F.remove(Entries, I.getKey());
    }
  }
  state = state->set<CStringLength>(Entries);
  C.addTransition(state);
}
void ento::registerCStringModeling(CheckerManager &Mgr) {
  Mgr.registerChecker<CStringChecker>();
}
bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) {
  return true;
}
#define REGISTER_CHECKER(name)                                                 \
  void ento::register##name(CheckerManager &mgr) {                             \
    CStringChecker *checker = mgr.getChecker<CStringChecker>();                \
    checker->Filter.Check##name = true;                                        \
    checker->Filter.CheckName##name = mgr.getCurrentCheckerName();             \
  }                                                                            \
                                                                               \
  bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
REGISTER_CHECKER(CStringNullArg)
REGISTER_CHECKER(CStringOutOfBounds)
REGISTER_CHECKER(CStringBufferOverlap)
REGISTER_CHECKER(CStringNotNullTerm)
REGISTER_CHECKER(CStringUninitializedRead)