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 @@ -1888,6 +1888,30 @@ return svalBuilder.makeIntVal(Code, ElemT); } +static Optional getDerivedSymbolForBinding( + RegionBindingsConstRef B, const TypedValueRegion *BaseRegion, + const TypedValueRegion *SubReg, const ASTContext &Ctx, SValBuilder &SVB) { + assert(BaseRegion); + QualType BaseTy = BaseRegion->getValueType(); + QualType Ty = SubReg->getValueType(); + if (BaseTy->isScalarType() && Ty->isScalarType()) { + if (Ctx.getTypeSizeInChars(BaseTy) >= Ctx.getTypeSizeInChars(Ty)) { + if (const Optional &ParentValue = B.getDirectBinding(BaseRegion)) { + if (SymbolRef ParentValueAsSym = ParentValue->getAsSymbol()) + return SVB.getDerivedRegionValueSymbolVal(ParentValueAsSym, SubReg); + + if (ParentValue->isUndef()) + return UndefinedVal(); + + // Other cases: give up. We are indexing into a larger object + // that has some value, but we don't know how to handle that yet. + return UnknownVal(); + } + } + } + return None; +} + SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B, const ElementRegion* R) { // Check if the region has a binding. @@ -1932,27 +1956,10 @@ if (!O.getRegion()) return UnknownVal(); - if (const TypedValueRegion *baseR = - dyn_cast_or_null(O.getRegion())) { - QualType baseT = baseR->getValueType(); - if (baseT->isScalarType()) { - QualType elemT = R->getElementType(); - if (elemT->isScalarType()) { - if (Ctx.getTypeSizeInChars(baseT) >= Ctx.getTypeSizeInChars(elemT)) { - if (const Optional &V = B.getDirectBinding(superR)) { - if (SymbolRef parentSym = V->getAsSymbol()) - return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R); - - if (V->isUnknownOrUndef()) - return *V; - // Other cases: give up. We are indexing into a larger object - // that has some value, but we don't know how to handle that yet. - return UnknownVal(); - } - } - } - } - } + if (const TypedValueRegion *baseR = dyn_cast(O.getRegion())) + if (auto V = getDerivedSymbolForBinding(B, baseR, R, Ctx, svalBuilder)) + return *V; + return getBindingForFieldOrElementCommon(B, R, R->getElementType()); } @@ -1988,6 +1995,26 @@ } } + // Handle the case where we are accessing into a larger scalar object. + // For example, this handles: + // struct header { + // unsigned a : 1; + // unsigned b : 1; + // }; + // struct parse_t { + // unsigned bits0 : 1; + // unsigned bits2 : 2; // <-- header + // unsigned bits4 : 4; + // }; + // int parse(parse_t *p) { + // unsigned copy = p->bits2; + // header *bits = (header *)© + // return bits->b; <-- here + // } + if (const auto *Base = dyn_cast(R->getBaseRegion())) + if (auto V = getDerivedSymbolForBinding(B, Base, R, Ctx, svalBuilder)) + return *V; + return getBindingForFieldOrElementCommon(B, R, Ty); } 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,7 @@ // RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm -verify %s + +template void clang_analyzer_dump(T); + struct X { int *p; int zero; @@ -117,3 +120,24 @@ auto n = p - reinterpret_cast((__UINTPTR_TYPE__)1); return n == m; } + +namespace Bug_55934 { +struct header { + unsigned a : 1; + unsigned b : 1; +}; +struct parse_t { + unsigned bits0 : 1; + unsigned bits2 : 2; // <-- header + unsigned bits4 : 4; +}; +int parse(parse_t *p) { + unsigned copy = p->bits2; + clang_analyzer_dump(copy); + // expected-warning@-1 {{reg_$1}.bits2>}} + header *bits = (header *)© + clang_analyzer_dump(bits->b); + // expected-warning@-1 {{derived_$2{reg_$1}.bits2>,Element{copy,0 S64b,struct Bug_55934::header}.b}}} + return bits->b; // no-warning +} +} // namespace Bug_55934