Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -154,6 +154,7 @@ class RegionBindingsRef : public llvm::ImmutableMapRef { ClusterBindings::Factory *CBFactory; + bool IsMainAnalysis; public: typedef llvm::ImmutableMapRef @@ -161,22 +162,25 @@ RegionBindingsRef(ClusterBindings::Factory &CBFactory, const RegionBindings::TreeTy *T, - RegionBindings::TreeTy::Factory *F) + RegionBindings::TreeTy::Factory *F, + bool IsMainAnalysis) : llvm::ImmutableMapRef(T, F), - CBFactory(&CBFactory) {} + CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {} - RegionBindingsRef(const ParentTy &P, ClusterBindings::Factory &CBFactory) + RegionBindingsRef(const ParentTy &P, + ClusterBindings::Factory &CBFactory, + bool IsMainAnalysis) : llvm::ImmutableMapRef(P), - CBFactory(&CBFactory) {} + CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {} RegionBindingsRef add(key_type_ref K, data_type_ref D) const { return RegionBindingsRef(static_cast(this)->add(K, D), - *CBFactory); + *CBFactory, IsMainAnalysis); } RegionBindingsRef remove(key_type_ref K) const { return RegionBindingsRef(static_cast(this)->remove(K), - *CBFactory); + *CBFactory, IsMainAnalysis); } RegionBindingsRef addBinding(BindingKey K, SVal V) const; @@ -206,7 +210,14 @@ /// Return the internal tree as a Store. Store asStore() const { - return asImmutableMap().getRootWithoutRetain(); + static_assert(alignof(decltype(*asImmutableMap().getRootWithoutRetain())) > 1, + "No room for the flag!"); + return (Store)((uintptr_t)(asImmutableMap().getRootWithoutRetain()) | + (uintptr_t)(IsMainAnalysis)); + } + + bool isMainAnalysis() const { + return IsMainAnalysis; } void printJson(raw_ostream &Out, const char *NL = "\n", @@ -382,7 +393,12 @@ SVal ArrayToPointer(Loc Array, QualType ElementTy) override; StoreRef getInitialStore(const LocationContext *InitLoc) override { - return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this); + bool IsMainAnalysis = false; + if (const auto *FD = dyn_cast(InitLoc->getDecl())) + IsMainAnalysis = FD->isMain() && !Ctx.getLangOpts().CPlusPlus; + return StoreRef(RegionBindingsRef( + RegionBindingsRef::ParentTy(RBFactory.getEmptyMap(), RBFactory), + CBFactory, IsMainAnalysis).asStore(), *this); } //===-------------------------------------------------------------------===// @@ -608,9 +624,10 @@ //===------------------------------------------------------------------===// RegionBindingsRef getRegionBindings(Store store) const { - return RegionBindingsRef(CBFactory, - static_cast(store), - RBFactory.getTreeFactory()); + return RegionBindingsRef( + CBFactory, + (const RegionBindings::TreeTy *)((uintptr_t)store & ~(uintptr_t)1), + RBFactory.getTreeFactory(), (bool)((uintptr_t)store & (uintptr_t)1)); } void printJson(raw_ostream &Out, Store S, const char *NL = "\n", @@ -1674,7 +1691,9 @@ // Check if the containing array is const and has an initialized value. const VarDecl *VD = VR->getDecl(); // Either the array or the array element has to be const. - if (VD->getType().isConstQualified() || R->getElementType().isConstQualified()) { + if (VD->getType().isConstQualified() || + R->getElementType().isConstQualified() || + (B.isMainAnalysis() && VD->hasGlobalStorage())) { if (const Expr *Init = VD->getAnyInitializer()) { if (const auto *InitList = dyn_cast(Init)) { // The array index has to be known. @@ -1764,7 +1783,8 @@ QualType RecordVarTy = VD->getType(); unsigned Index = FD->getFieldIndex(); // Either the record variable or the field has to be const qualified. - if (RecordVarTy.isConstQualified() || Ty.isConstQualified()) + if (RecordVarTy.isConstQualified() || Ty.isConstQualified() || + (B.isMainAnalysis() && VD->hasGlobalStorage())) if (const Expr *Init = VD->getAnyInitializer()) if (const auto *InitList = dyn_cast(Init)) { if (Index < InitList->getNumInits()) { @@ -1982,6 +2002,11 @@ if (isa(MS)) { QualType T = VD->getType(); + if (B.isMainAnalysis()) + if (const Expr *Init = VD->getAnyInitializer()) + if (Optional V = svalBuilder.getConstantVal(Init)) + return *V; + // Function-scoped static variables are default-initialized to 0; if they // have an initializer, it would have been processed by now. // FIXME: This is only true when we're starting analysis from main(). Index: clang/test/Analysis/main.c =================================================================== --- /dev/null +++ clang/test/Analysis/main.c @@ -0,0 +1,21 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s + +int x = 1; + +struct { + int a, b; +} s = {2, 3}; + +int arr[] = {4, 5, 6}; + +void clang_analyzer_eval(int); + +int main() { + clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} + clang_analyzer_eval(s.a == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(s.b == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(arr[0] == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(arr[1] == 5); // expected-warning{{TRUE}} + clang_analyzer_eval(arr[2] == 6); // expected-warning{{TRUE}} + return 0; +} Index: clang/test/Analysis/main.cpp =================================================================== --- /dev/null +++ clang/test/Analysis/main.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s + +int x = 1; + +struct { + int a, b; +} s = {2, 3}; + +int arr[] = {4, 5, 6}; + +void clang_analyzer_eval(int); + +int main() { + // Do not trust global initializers in C++. + clang_analyzer_eval(x == 1); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + clang_analyzer_eval(s.a == 2); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + clang_analyzer_eval(s.b == 3); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + clang_analyzer_eval(arr[0] == 4); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + clang_analyzer_eval(arr[1] == 5); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + clang_analyzer_eval(arr[2] == 6); // expected-warning{{TRUE}} // expected-warning{{FALSE}} + return 0; +}