diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 03cc20f..6969eac 100644
--- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -23,10 +23,12 @@ using namespace ento;
 
 namespace {
 class CStringChecker : public CheckerVisitor<CStringChecker> {
-  BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
+  BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString,
+    *BT_PotentialBoundsWrite;
 public:
   CStringChecker()
-  : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
+    : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), 
+      BT_NotCString(0), BT_PotentialBoundsWrite(0)
   {}
   static void *getTag() { static int tag; return &tag; }
 
@@ -82,7 +84,8 @@ public:
                                const Expr *S, SVal l);
   const GRState *CheckLocation(CheckerContext &C, const GRState *state,
                                const Expr *S, SVal l,
-                               bool IsDestination = false);
+                               bool IsDestination = false,
+                               bool IsPotential = false);
   const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
                                    const Expr *Size,
                                    const Expr *FirstBuf,
@@ -170,7 +173,8 @@ const GRState *CStringChecker::checkNonNull(CheckerContext &C,
 const GRState *CStringChecker::CheckLocation(CheckerContext &C,
                                              const GRState *state,
                                              const Expr *S, SVal l,
-                                             bool IsDestination) {
+                                             bool IsDestination,
+                                             bool IsPotential) {
   // If a previous check has failed, propagate the failure.
   if (!state)
     return NULL;
@@ -205,11 +209,21 @@ const GRState *CStringChecker::CheckLocation(CheckerContext &C,
 
     BuiltinBug *BT;
     if (IsDestination) {
-      if (!BT_BoundsWrite) {
-        BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
-          "Byte string function overflows destination buffer");
+      if (IsPotential) {
+        if (!BT_PotentialBoundsWrite) {
+          BT_PotentialBoundsWrite = 
+            new BuiltinBug("Out-of-bound array access",
+              "Max number of bytes copied would overflow destination buffer");
+        }
+        BT = static_cast<BuiltinBug*>(BT_PotentialBoundsWrite);
+      }
+      else {
+        if (!BT_BoundsWrite) {
+          BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
+            "Byte string function overflows destination buffer");
+        }
+        BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
       }
-      BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
     } else {
       if (!BT_Bounds) {
         BT_Bounds = new BuiltinBug("Out-of-bound array access",
@@ -842,13 +856,16 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
   if (strLength.isUndef())
     return;
 
+  NonLoc * lenValNL;
+  SVal lenVal;
+  bool checkPotentialLen = false;
   if (isStrncpy) {
     // Get the max number of characters to copy
     const Expr *lenExpr = CE->getArg(2);
-    SVal lenVal = state->getSVal(lenExpr);
-
+    lenVal = state->getSVal(lenExpr);
+    
     NonLoc * strLengthNL = dyn_cast<NonLoc>(&strLength);
-    NonLoc * lenValNL = dyn_cast<NonLoc>(&lenVal);
+    lenValNL = dyn_cast<NonLoc>(&lenVal);
 
     QualType cmpTy = C.getSValBuilder().getContext().IntTy;
     const GRState *stateTrue, *stateFalse;
@@ -856,7 +873,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
     // Check if the max number to copy is less than the length of the src
     llvm::tie(stateTrue, stateFalse) =
       state->assume(cast<DefinedOrUnknownSVal>
-                    (C.getSValBuilder().evalBinOpNN(state, BO_GT, 
+                    (C.getSValBuilder().evalBinOpNN(state, BO_GE, 
                                                     *strLengthNL, *lenValNL,
                                                     cmpTy)));
 
@@ -864,7 +881,9 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
       // Max number to copy is less than the length of the src, so the actual
       // strLength copied is the max number arg.
       strLength = lenVal;
-    }    
+    } else {
+      checkPotentialLen = true;
+    }
   }
 
   SVal Result = (returnEnd ? UnknownVal() : DstVal);
@@ -887,6 +906,17 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
         Result = lastElement;
     }
 
+    // Max number to copy is greater than the length of the src buffer. So
+    // also check that it is still <= length of destination buffer.
+    if (checkPotentialLen) {
+      SVal lastElement =
+        C.getSValBuilder().evalBinOpLN(state, BO_Add, *dstRegVal,
+                                       *lenValNL, Dst->getType());
+      
+      CheckLocation(C, state, Dst, lastElement, /* IsDst = */ true,
+                    /* IsPotential = */ true);
+    }
+
     // Invalidate the destination. This must happen before we set the C string
     // length because invalidation will clear the length.
     // FIXME: Even if we can't perfectly model the copy, we should see if we
diff --git a/test/Analysis/string.c b/test/Analysis/string.c
index c411a5e..44508bd 100644
--- a/test/Analysis/string.c
+++ b/test/Analysis/string.c
@@ -248,7 +248,7 @@ void strncpy_overflow(char *y) {
 void strncpy_len_overflow(char *y) {
   char x[4];
   if (strlen(y) == 3)
-    strncpy(x, y, sizeof(x)); // no-warning
+    strncpy(x, y, sizeof(x)); // expected-warning{{Max number of bytes copied would overflow destination buffer}}
 }
 
 void strncpy_no_overflow(char *y) {
