From 1acb394679b6e644044a0f6c358229759009b1a6 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Wed, 29 May 2013 20:50:34 +0000 Subject: [PATCH] [analyzer] Accept references to variables declared "extern void" (C only). 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 | 4 +++- lib/StaticAnalyzer/Core/MemRegion.cpp | 2 +- test/Analysis/misc-ps.c | 18 +++++++++++++++++- test/Analysis/out-of-bounds.c | 12 ++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index bfe4e15a71..627e0107b8 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1613,7 +1613,9 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, const LocationContext *LCtx = Pred->getLocationContext(); if (const VarDecl *VD = dyn_cast(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 diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 31ac86bea6..0102f9237c 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -186,7 +186,7 @@ DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const if (isa(T)) return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); - if (isa(T)) + if (T->isIncompleteType()) return UnknownVal(); CharUnits size = Ctx.getTypeSizeInChars(T); diff --git a/test/Analysis/misc-ps.c b/test/Analysis/misc-ps.c index b302860a2f..01cad1549c 100644 --- a/test/Analysis/misc-ps.c +++ b/test/Analysis/misc-ps.c @@ -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}} +} diff --git a/test/Analysis/out-of-bounds.c b/test/Analysis/out-of-bounds.c index dd593c5f26..d89a239619 100644 --- a/test/Analysis/out-of-bounds.c +++ b/test/Analysis/out-of-bounds.c @@ -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 +} + -- 2.40.0