[PATCH] D28765: CStringChecker can crash when uninitialized checks are disabled

Vlad Tsyrklevich via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 16 03:09:43 PST 2017


vlad.tsyrklevich created this revision.
vlad.tsyrklevich added reviewers: cfe-commits, zaks.anna, dcoughlin, NoQ.

CStringChecker assumes that SVals are not undefined at two points with comments stating that other checkers will check for that condition first; however, it can crash if a user chooses a particular configuration. I hit such an unlucky configuration while eliminating false positive heavy checks analyzing the Linux kernel and tracked down the crashes to this assumption.

Add UndefinedVal checks where appropriate.


https://reviews.llvm.org/D28765

Files:
  lib/StaticAnalyzer/Checkers/CStringChecker.cpp
  test/Analysis/cstring-regressions.c


Index: test/Analysis/cstring-regressions.c
===================================================================
--- /dev/null
+++ test/Analysis/cstring-regressions.c
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,debug.ExprInspection -analyzer-disable-checker=core.UndefinedBinaryOperatorResult,core.CallAndMessage,core.NullDereference,core.uninitialized -analyzer-store=region -verify %s
+//
+// CStringChecker crashes found running analyzer over the Linux kernel source
+// with a very particular set of enabled/disabled checks.
+
+int strcmp(const char * s1, const char * s2);
+int memcmp(const void *s1, const void *s2, unsigned long n);
+void clang_analyzer_eval(int);
+
+void test1(void *ptr) {
+ int uninit;
+ clang_analyzer_eval(strcmp(ptr + uninit, "mcp_trace_meta") == 0); // expected-warning{{UNKNOWN}}
+}
+
+void test2(char *foo, void *ptr) {
+ int uninit;
+ clang_analyzer_eval(memcmp(foo, ptr + uninit, 48) == 0); // expected-warning{{UNKNOWN}}
+}
Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -1179,15 +1179,17 @@
   if (stateNonZeroSize) {
     state = stateNonZeroSize;
     // If we know the two buffers are the same, we know the result is 0.
-    // First, get the two buffers' addresses. Another checker will have already
-    // made sure they're not undefined.
-    DefinedOrUnknownSVal LV =
-        state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>();
-    DefinedOrUnknownSVal RV =
-        state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>();
+    // First, get the two buffers' addresses.
+    Optional<DefinedOrUnknownSVal> LV =
+        state->getSVal(Left, LCtx).getAs<DefinedOrUnknownSVal>();
+    Optional<DefinedOrUnknownSVal> RV =
+        state->getSVal(Right, LCtx).getAs<DefinedOrUnknownSVal>();
+
+    if (!LV || !RV)
+      return;
 
     // See if they are the same.
-    DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
+    DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, *LV, *RV);
     ProgramStateRef StSameBuf, StNotSameBuf;
     std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
 
@@ -1781,13 +1783,19 @@
   // Check that the first string is non-null
   const Expr *s1 = CE->getArg(0);
   SVal s1Val = state->getSVal(s1, LCtx);
+  if (s1Val.isUndef())
+    return;
+
   state = checkNonNull(C, state, s1, s1Val);
   if (!state)
     return;
 
   // Check that the second string is non-null.
   const Expr *s2 = CE->getArg(1);
   SVal s2Val = state->getSVal(s2, LCtx);
+  if (s2Val.isUndef())
+    return;
+
   state = checkNonNull(C, state, s2, s2Val);
   if (!state)
     return;
@@ -1803,8 +1811,7 @@
     return;
 
   // If we know the two buffers are the same, we know the result is 0.
-  // First, get the two buffers' addresses. Another checker will have already
-  // made sure they're not undefined.
+  // First, get the two buffers' addresses.
   DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>();
   DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>();
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D28765.84534.patch
Type: text/x-patch
Size: 3200 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170116/c278041c/attachment.bin>


More information about the cfe-commits mailing list