]> granicus.if.org Git - clang/commitdiff
[analyzer] Accept references to variables declared "extern void" (C only).
authorJordan Rose <jordan_rose@apple.com>
Wed, 29 May 2013 20:50:34 +0000 (20:50 +0000)
committerJordan Rose <jordan_rose@apple.com>
Wed, 29 May 2013 20:50:34 +0000 (20:50 +0000)
In C, 'void' is treated like any other incomplete type, and though it is
never completed, you can cast the address of a void-typed variable to do
something useful. (In C++ it's illegal to declare a variable with void type.)

Previously we asserted on this code; now we just treat it like any other
incomplete type.

And speaking of incomplete types, we don't know their extent. Actually
check that in TypedValueRegion::getExtent, though that's not being used
by any checkers that are on by default.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182880 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/MemRegion.cpp
test/Analysis/misc-ps.c
test/Analysis/out-of-bounds.c

index bfe4e15a7156bc3e8c71925766237a4860ef80d3..627e0107b86252c9c33a0db5c3cf559c8d1400a9 100644 (file)
@@ -1613,7 +1613,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
   const LocationContext *LCtx = Pred->getLocationContext();
 
   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
-    assert(Ex->isGLValue());
+    // C permits "extern void v", and if you cast the address to a valid type,
+    // you can even do things with it. We simply pretend 
+    assert(Ex->isGLValue() || VD->getType()->isVoidType());
     SVal V = state->getLValue(VD, Pred->getLocationContext());
 
     // For references, the 'lvalue' is the pointer address stored in the
index 31ac86bea663d2016e3d3ddeb57e607d0686bd22..0102f9237c20ce4ef5c2fe8b5c95d45bea48dfbd 100644 (file)
@@ -186,7 +186,7 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const
 
   if (isa<VariableArrayType>(T))
     return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this));
-  if (isa<IncompleteArrayType>(T))
+  if (T->isIncompleteType())
     return UnknownVal();
 
   CharUnits size = Ctx.getTypeSizeInChars(T);
index b302860a2f97e06deaa693335b07e874d8310093..01cad1549cda4435b9374fbfc1c6181e85a2cb55 100644 (file)
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=deadcode -verify %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -analyze -disable-free -analyzer-eagerly-assume -analyzer-checker=core,deadcode,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 int size_rdar9373039 = 1;
 int foo_rdar9373039(const char *);
@@ -175,3 +177,17 @@ void sinkAfterRegularNode(struct PR15684 *context) {
   context->callback(uninitialized); // expected-warning {{uninitialized}}
 }
 
+
+// PR16131: C permits variables to be declared extern void.
+static void PR16131(int x) {
+  extern void v;
+
+  int *ip = (int *)&v;
+  char *cp = (char *)&v;
+  clang_analyzer_eval(ip == cp); // expected-warning{{TRUE}}
+  // expected-warning@-1 {{comparison of distinct pointer types}}
+
+  *ip = 42;
+  clang_analyzer_eval(*ip == 42); // expected-warning{{TRUE}}
+  clang_analyzer_eval(*(int *)&v == 42); // expected-warning{{TRUE}}
+}
index dd593c5f26c04842f3f53c14c68f80b1d545edc2..d89a23961903b6088b681fe59ef5cb672837fb16 100644 (file)
@@ -154,3 +154,15 @@ void test_index_below_symboloc() {
   buf[-1] = 0; // no-warning;
 }
 
+void test_incomplete_struct() {
+  extern struct incomplete incomplete;
+  int *p = (int *)&incomplete;
+  p[1] = 42; // no-warning
+}
+
+void test_extern_void() {
+  extern void v;
+  int *p = (int *)&v;
+  p[1] = 42; // no-warning
+}
+