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() || BTy->isRecordType()) + 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/array-punned-region.c =================================================================== --- clang/test/Analysis/array-punned-region.c +++ clang/test/Analysis/array-punned-region.c @@ -12,7 +12,7 @@ void array_struct_bitfield_1() { BITFIELD_CAST ff = {0}; BITFIELD_CAST *pff = &ff; - clang_analyzer_eval(*((int *)pff + 1) == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(*((int *)pff + 1) == 0); // expected-warning{{UNKNOWN}} ff.b[0] = 3; clang_analyzer_eval(*((int *)pff + 1) == 3); // expected-warning{{TRUE}} } @@ -20,7 +20,13 @@ int array_struct_bitfield_2() { BITFIELD_CAST ff = {0}; BITFIELD_CAST *pff = &ff; - int a = *((int *)pff + 2); // expected-warning{{Assigned value is garbage or undefined [core.uninitialized.Assign]}} + int a = *((int *)pff + 2); // no-warning + + clang_analyzer_eval(((int *)pff + 2) == &ff.b[1]); // expected-warning{{TRUE}} + clang_analyzer_eval(ff.b[1] == 0); // expected-warning{{TRUE}} + // FIXME: this should be TRUE + clang_analyzer_eval(a == 0); // expected-warning{{UNKNOWN}} + return a; } 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 { @@ -52,8 +48,7 @@ struct st *p2; p1 = (&s2) + 1; - p2 = mempcpy(&s2, &s1, sizeof(struct st)); // expected-warning{{Bytes string function accesses uninitialized/garbage values}} - // FIXME: It seems same as mempcpy14() case. - - clang_analyzer_eval(p1 == p2); // no-warning (above is fatal) + p2 = mempcpy(&s2, &s1, sizeof(struct st)); + + clang_analyzer_eval(p1 == p2); // expected-warning{{TRUE}} } 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);