[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.

llvm-svn: 182880
This commit is contained in:
Jordan Rose 2013-05-29 20:50:34 +00:00
parent 33b736626e
commit 1bd1927a14
4 changed files with 33 additions and 3 deletions

View 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

View 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);

View 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}}
}

View 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
}