diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1414,19 +1414,20 @@ return UnknownVal(); } - if (!isa(MR)) { - if (T.isNull()) { - if (const TypedRegion *TR = dyn_cast(MR)) - T = TR->getLocationType()->getPointeeType(); - else if (const SymbolicRegion *SR = dyn_cast(MR)) - T = SR->getPointeeStaticType(); - } - assert(!T.isNull() && "Unable to auto-detect binding type!"); - assert(!T->isVoidType() && "Attempting to dereference a void pointer!"); + // Auto-detect the binding type. + if (T.isNull()) { + if (const auto *TVR = dyn_cast(MR)) + T = TVR->getValueType(); + else if (const auto *TR = dyn_cast(MR)) + T = TR->getLocationType()->getPointeeType(); + else if (const auto *SR = dyn_cast(MR)) + T = SR->getPointeeStaticType(); + } + assert(!T.isNull() && "Unable to auto-detect binding type!"); + assert(!T->isVoidType() && "Attempting to dereference a void pointer!"); + + if (!isa(MR)) MR = GetElementZeroRegion(cast(MR), T); - } else { - T = cast(MR)->getValueType(); - } // FIXME: Perhaps this method should just take a 'const MemRegion*' argument // instead of 'Loc', and have the other Loc cases handled at a higher level. diff --git a/clang/test/Analysis/ptr-arith.cpp b/clang/test/Analysis/ptr-arith.cpp --- a/clang/test/Analysis/ptr-arith.cpp +++ b/clang/test/Analysis/ptr-arith.cpp @@ -1,4 +1,9 @@ -// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm -verify %s +// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -verify %s -triple x86_64-pc-linux-gnu \ +// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm + +// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -verify %s -triple x86_64-pc-linux-gnu \ +// RUN: -analyzer-config support-symbolic-integer-casts=true \ +// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm template void clang_analyzer_dump(T); @@ -141,3 +146,22 @@ return bits->b; // no-warning } } // namespace Bug_55934 + +void LValueToRValueBitCast_dumps(void *p, char (*array)[8]) { + clang_analyzer_dump(p); + clang_analyzer_dump(array); + // expected-warning@-2 {{&SymRegion{reg_$0}}} + // expected-warning@-2 {{&SymRegion{reg_$1}}} + clang_analyzer_dump((unsigned long)p); + clang_analyzer_dump(__builtin_bit_cast(unsigned long, p)); + // expected-warning@-2 {{&SymRegion{reg_$0} [as 64 bit integer]}} + // expected-warning@-2 {{&SymRegion{reg_$0} [as 64 bit integer]}} + clang_analyzer_dump((unsigned long)array); + clang_analyzer_dump(__builtin_bit_cast(unsigned long, array)); + // expected-warning@-2 {{&SymRegion{reg_$1} [as 64 bit integer]}} + // expected-warning@-2 {{&SymRegion{reg_$1} [as 64 bit integer]}} +} + +unsigned long ptr_arithmetic(void *p) { + return __builtin_bit_cast(unsigned long, p) + 1; // no-crash +} diff --git a/clang/test/Analysis/svalbuilder-float-cast.c b/clang/test/Analysis/svalbuilder-float-cast.c --- a/clang/test/Analysis/svalbuilder-float-cast.c +++ b/clang/test/Analysis/svalbuilder-float-cast.c @@ -1,16 +1,25 @@ // RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -Wno-deprecated-non-prototype -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -Wno-deprecated-non-prototype -verify %s \ +// RUN: -analyzer-config support-symbolic-integer-casts=true + void clang_analyzer_denote(int, const char *); void clang_analyzer_express(int); +void clang_analyzer_dump(int); +void clang_analyzer_dump_ptr(int *); void SymbolCast_of_float_type_aux(int *p) { + clang_analyzer_dump_ptr(p); // expected-warning {{&x}} + clang_analyzer_dump(*p); // expected-warning {{Unknown}} + // Storing to the memory region of 'float x' as 'int' will + // materialize a fresh conjured symbol to regain accuracy. *p += 0; - // FIXME: Ideally, all unknown values should be symbolicated. - clang_analyzer_denote(*p, "$x"); // expected-warning{{Not a symbol}} + clang_analyzer_dump_ptr(p); // expected-warning {{&x}} + clang_analyzer_dump(*p); // expected-warning {{conj_$0{int}} + clang_analyzer_denote(*p, "$x"); *p += 1; // This should NOT be (float)$x + 1. Symbol $x was never casted to float. - // FIXME: Ideally, this should be $x + 1. - clang_analyzer_express(*p); // expected-warning{{Not a symbol}} + clang_analyzer_express(*p); // expected-warning{{$x + 1}} } void SymbolCast_of_float_type(void) {