From: Ted Kremenek Date: Thu, 6 Aug 2009 21:43:54 +0000 (+0000) Subject: Fix a couple false positive "uninitialized value" warnings with RegionStore X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d4e5a606c9c64e24c05e5f4610796087e911fb9c;p=clang Fix a couple false positive "uninitialized value" warnings with RegionStore involving reasoning about unions (which we don't handle yet). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78342 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/Support/Optional.h b/include/clang/Analysis/Support/Optional.h new file mode 100644 index 0000000000..5fb5078f76 --- /dev/null +++ b/include/clang/Analysis/Support/Optional.h @@ -0,0 +1,55 @@ +//===-- Optional.h - Simple variant for passing optional values ---*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides Optional, a template class modeled in the spirit of +// OCaml's 'opt' variant. The idea is to strongly type whether or not +// a value can be optional. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_OPTIONAL +#define LLVM_CLANG_ANALYSIS_OPTIONAL + +namespace clang { + +template +class Optional { + const T x; + unsigned hasVal : 1; +public: + explicit Optional() : hasVal(false) {} + Optional(const T &y) : x(y), hasVal(true) {} + + static inline Optional create(const T* y) { + return y ? Optional(*y) : Optional(); + } + + const T* getPointer() const { assert(hasVal); return &x; } + + operator bool() const { return hasVal; } + const T* operator->() const { return getPointer(); } + const T& operator*() const { assert(hasVal); return x; } +}; +} //end clang namespace + +namespace llvm { +template +struct simplify_type > { + typedef const T* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::Optional &Val) { + return Val.getPointer(); + } +}; + +template +struct simplify_type< ::clang::Optional > + : public simplify_type > {}; +} // end llvm namespace + +#endif diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp index 3216756045..8cb4d98021 100644 --- a/lib/Analysis/RegionStore.cpp +++ b/lib/Analysis/RegionStore.cpp @@ -18,6 +18,7 @@ #include "clang/Analysis/PathSensitive/GRState.h" #include "clang/Analysis/PathSensitive/GRStateTrait.h" #include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Support/Optional.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ImmutableMap.h" @@ -187,6 +188,11 @@ public: RegionStoreSubRegionMap *getRegionStoreSubRegionMap(const GRState *state); + + /// getDefaultBinding - Returns an SVal* representing an optional default + /// binding associated with a region and its subregions. + Optional getDefaultBinding(const GRState *state, const MemRegion *R); + /// getLValueString - Returns an SVal representing the lvalue of a /// StringLiteral. Within RegionStore a StringLiteral has an /// associated StringRegion, and the lvalue of a StringLiteral is @@ -829,6 +835,17 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state, // Loading values from regions. //===----------------------------------------------------------------------===// +Optional RegionStoreManager::getDefaultBinding(const GRState *state, + const MemRegion *R) { + + if (R->isBoundable()) + if (const TypedRegion *TR = dyn_cast(R)) + if (TR->getValueType(getContext())->isUnionType()) + return UnknownVal(); + + return Optional::create(state->get(R)); +} + static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) { RTy = Ctx.getCanonicalType(RTy); UsedTy = Ctx.getCanonicalType(UsedTy); @@ -911,6 +928,10 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) { if (RTy->isStructureType()) return SValuator::CastResult(state, RetrieveStruct(state, R)); + + // FIXME: Handle unions. + if (RTy->isUnionType()) + return SValuator::CastResult(state, UnknownVal()); if (RTy->isArrayType()) return SValuator::CastResult(state, RetrieveArray(state, R)); @@ -1109,7 +1130,7 @@ SVal RegionStoreManager::RetrieveField(const GRState* state, const MemRegion* superR = R->getSuperRegion(); while (superR) { - if (const SVal* D = state->get(superR)) { + if (const Optional &D = getDefaultBinding(state, superR)) { if (SymbolRef parentSym = D->getAsSymbol()) return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R); diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m index af6e53b1de..9f639ea610 100644 --- a/test/Analysis/misc-ps-region-store.m +++ b/test/Analysis/misc-ps-region-store.m @@ -32,10 +32,12 @@ extern NSString * const NSConnectionReplyMode; // PR 2948 (testcase; crash on VisitLValue for union types) // http://llvm.org/bugs/show_bug.cgi?id=2948 - void checkaccess_union() { int ret = 0, status; - if (((((__extension__ (((union { // expected-warning {{ Branch condition evaluates to an uninitialized value.}} + // Since RegionStore doesn't handle unions yet, + // this branch condition won't be triggered + // as involving an uninitialized value. + if (((((__extension__ (((union { // no-warning __typeof (status) __in; int __i;} ) { @@ -44,7 +46,6 @@ void checkaccess_union() { ret = 1; } - // Check our handling of fields being invalidated by function calls. struct test2_struct { int x; int y; char* s; }; void test2_helper(struct test2_struct* p); diff --git a/test/Analysis/unions-region.m b/test/Analysis/unions-region.m new file mode 100644 index 0000000000..d253009d8b --- /dev/null +++ b/test/Analysis/unions-region.m @@ -0,0 +1,32 @@ +// RUN: clang-cc -analyze -checker-cfref -analyzer-store=region -analyzer-constraints=range %s -verify + +//===-- unions-region.m ---------------------------------------------------===// +// +// This file tests the analyzer's reasoning about unions. +// +//===----------------------------------------------------------------------===// + +// When using RegionStore, this test case previously had a false positive +// of a 'pass-by-value argument is uninitialized' warning at the call to +// 'testA_aux'. + +union u_testA { + unsigned i; + float f; +}; + +float testA(float f) { + int testA_aux(unsigned x); + int testA_aux_2(union u_testA z); + + union u_testA swap; + swap.f = f; + + if (testA_aux(swap.i)) // no-warning + swap.i = ((swap.i & 0xffff0000) >> 16) | ((swap.i & 0x0000fffff) << 16); + + testA_aux_2(swap); // no-warning + + return swap.f; +} +