Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1393,6 +1393,47 @@ // Loading values from regions. //===----------------------------------------------------------------------===// +static bool isFunny(const MemRegion *MR, const ASTContext &C) { + const auto *EL = dyn_cast_or_null(MR); + if (!EL) + return false; + + if (const auto *Base = + dyn_cast_or_null(EL->getSuperRegion())) { + const auto BTy = Base->getValueType() + .getDesugaredType(C) + .getUnqualifiedType() + .getCanonicalType(); + + const auto Ty = EL->getValueType() + .getDesugaredType(C) + .getUnqualifiedType() + .getCanonicalType(); + + // Handle array types. + if (const auto *AT = dyn_cast(BTy)) { + QualType ETy; + while (AT) { + ETy = AT->getElementType() + .getDesugaredType(C) + .getUnqualifiedType() + .getCanonicalType(); + AT = dyn_cast(ETy); + } + + return ETy != Ty; + } + + // Handle fundamental types. + if (BTy->isFundamentalType()) + return BTy != Ty; + + // FIXME: Handle other types as well + }; + + return false; +} + SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T) { assert(!isa(L) && "location unknown"); assert(!isa(L) && "location undefined"); @@ -1448,6 +1489,11 @@ // char c = *q; // returns the first byte of 'x'. // // Such funny addressing will occur due to layering of regions. + // For now let's just prevent false positives. If the region has a direct + // binding, ignore if it's funny. + if (isFunny(R, svalBuilder.getContext()) && !B.lookup(R, BindingKey::Direct)) + return UnknownVal(); + if (RTy->isStructureOrClassType()) return getBindingForStruct(B, R); Index: clang/test/Analysis/bstring_UninitRead.c =================================================================== --- clang/test/Analysis/bstring_UninitRead.c +++ clang/test/Analysis/bstring_UninitRead.c @@ -1,6 +1,5 @@ // RUN: %clang_analyze_cc1 -verify %s \ -// RUN: -analyzer-checker=core,alpha.unix.cstring - +// RUN: -analyzer-checker=core,alpha.unix.cstring,debug.ExprInspection // This file is generally for the alpha.unix.cstring.UninitializedRead Checker, the reason for putting it into // the separate file because the checker is break the some existing test cases in bstring.c file , so we don't @@ -31,12 +30,9 @@ int dst[5] = {0}; int *p; - p = mempcpy(dst, src, 4 * sizeof(int)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}} - // FIXME: This behaviour is actually surprising and needs to be fixed, - // mempcpy seems to consider the very last byte of the src buffer uninitialized - // and returning undef unfortunately. It should have returned unknown or a conjured value instead. + p = mempcpy(dst, src, 4 * sizeof(int)); - clang_analyzer_eval(p == &dst[4]); // no-warning (above is fatal) + clang_analyzer_eval(p == &dst[4]); // expected-warning{{TRUE}} } struct st { Index: clang/test/Analysis/casts.c =================================================================== --- clang/test/Analysis/casts.c +++ clang/test/Analysis/casts.c @@ -142,7 +142,8 @@ // FIXME: should be TRUE (i.e. same symbol). clang_analyzer_eval(*y1 == *y2); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(*((char *)y1) == *((char *) y2)); // expected-warning{{TRUE}} + // FIXME: should be TRUE + clang_analyzer_eval(*((char *)y1) == *((char *)y2)); // expected-warning{{UNKNOWN}} clang_analyzer_eval(y1 == y3); // expected-warning{{TRUE}} @@ -151,7 +152,8 @@ // FIXME: should be TRUE (i.e. same symbol). clang_analyzer_eval(*y1 == *y3); // expected-warning{{UNKNOWN}} - clang_analyzer_eval(*((char *)y1) == *((char *) y3)); // expected-warning{{TRUE}} + // FIXME: should be TRUE + clang_analyzer_eval(*((char *)y1) == *((char *)y3)); // expected-warning{{UNKNOWN}} } void *getVoidPtr(void);