[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-29 Thread Rafael Stahl via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rC333417: [analyzer] const init: handle non-explicit cases 
more accurately (authored by r.stahl, committed by ).

Repository:
  rC Clang

https://reviews.llvm.org/D46823

Files:
  lib/StaticAnalyzer/Core/RegionStore.cpp
  test/Analysis/initialization.c
  test/Analysis/initialization.cpp

Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can return
+// an undefined value.
+if (i < 0)
+  return UndefinedVal();
+
+if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+  if (CAT->getSize().sle(i))
+return UndefinedVal();
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());
 
 if (const Expr *ElemInit = InitList->getInit(i))
   if (Optional V = svalBuilder.getConstantVal(ElemInit))
@@ -1715,11 +1724,15 @@
 // Either the record variable or the field has to be const qualified.
 if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
   if (const Expr *Init = VD->getInit())
-if (const auto *InitList = dyn_cast(Init))
-  if (Index < InitList->getNumInits())
+if (const auto *InitList = dyn_cast(Init)) {
+  if (Index < InitList->getNumInits()) {
 if (const Expr *FieldInit = InitList->getInit(Index))
   if (Optional V = svalBuilder.getConstantVal(FieldInit))
 return *V;
+  } else {
+return svalBuilder.makeZeroVal(Ty);
+  }
+}
   }
 
   return getBindingForFieldOrElementCommon(B, R, Ty);
Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+  i = 1;
+  clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
+  i = -1;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
+}
Index: test/Analysis/initialization.cpp
===
--- test/Analysis/initialization.cpp
+++ test/Analysis/initialization.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+  int a = 3;
+};
+S const sarr[2] = {};
+void definit() {
+  int i = 1;
+  // FIXME: Should recognize that it is 3.
+  clang_analyzer_eval(sarr[i].a); // expected-warning{{UNKNOWN}}
+}
+
+int const arr[2][2] = {};
+void arr2init() {
+  int i = 1;
+  // FIXME: Should recognize that it is 0.
+  clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-28 Thread Rafael Stahl via Phabricator via cfe-commits
r.stahl updated this revision to Diff 148809.
r.stahl added a comment.

Added FIXME tests.

I know my example didn't exercise your scenario, but it was the only one I 
could think of where returning zero would have been straight up wrong. Note 
that I default initialized `a` to 3 there, so `sarr` is not just 
zero-initialized.

I do not have access yet, but applied today!


https://reviews.llvm.org/D46823

Files:
  lib/StaticAnalyzer/Core/RegionStore.cpp
  test/Analysis/initialization.c
  test/Analysis/initialization.cpp

Index: test/Analysis/initialization.cpp
===
--- test/Analysis/initialization.cpp
+++ test/Analysis/initialization.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+  int a = 3;
+};
+S const sarr[2] = {};
+void definit() {
+  int i = 1;
+  // FIXME: Should recognize that it is 3.
+  clang_analyzer_eval(sarr[i].a); // expected-warning{{UNKNOWN}}
+}
+
+int const arr[2][2] = {};
+void arr2init() {
+  int i = 1;
+  // FIXME: Should recognize that it is 0.
+  clang_analyzer_eval(arr[i][0]); // expected-warning{{UNKNOWN}}
+}
Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+  i = 1;
+  clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
+  i = -1;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
+}
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can return
+// an undefined value.
+if (i < 0)
+  return UndefinedVal();
+
+if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+  if (CAT->getSize().sle(i))
+return UndefinedVal();
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());
 
 if (const Expr *ElemInit = InitList->getInit(i))
   if (Optional V = svalBuilder.getConstantVal(ElemInit))
@@ -1715,11 +1724,15 @@
 // Either the record variable or the field has to be const qualified.
 if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
   if (const Expr *Init = VD->getInit())
-if (const auto *InitList = dyn_cast(Init))
-  if (Index < InitList->getNumInits())
+if (const auto *InitList = dyn_cast(Init)) {
+  if (Index < InitList->getNumInits()) {
 if (const Expr *FieldInit = InitList->getInit(Index))
   if (Optional V = svalBuilder.getConstantVal(FieldInit))
 return *V;
+  } else {
+return svalBuilder.makeZeroVal(Ty);
+  }
+}
   }
 
   return getBindingForFieldOrElementCommon(B, R, Ty);
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-25 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ accepted this revision.
NoQ added a comment.
This revision is now accepted and ready to land.

Looks good!

Do you have commit access? I think you should get commit access.




Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())

r.stahl wrote:
> r.stahl wrote:
> > NoQ wrote:
> > > NoQ wrote:
> > > > Would this work correctly if the element is not of an integral or 
> > > > enumeration type? I think this needs an explicit check.
> > > What if we have an out-of-bounds access to a variable-length array? I 
> > > don't think it'd yield zero.
> > I'm getting "variable-sized object may not be initialized", so this case 
> > should not be possible.
> I'm having a hard time reproducing this either.
> 
> 
> ```
> struct S {
>   int a = 3;
> };
> S const sarr[2] = {};
> void definit() {
>   int i = 1;
>   clang_analyzer_dump(sarr[i].a); // expected-warning{{test}}
> }
> ```
> 
> results in a symbolic value, because makeZeroVal returns an empty SVal list 
> for arrays, records, vectors and complex types. Otherwise it just returns 
> UnknownVal (for example for not-yet-implemented floats).
> 
> Can you think of a case where this would be an issue?
Yup, sounds reasonable.



Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650-1652
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());

NoQ wrote:
> r.stahl wrote:
> > r.stahl wrote:
> > > NoQ wrote:
> > > > NoQ wrote:
> > > > > Would this work correctly if the element is not of an integral or 
> > > > > enumeration type? I think this needs an explicit check.
> > > > What if we have an out-of-bounds access to a variable-length array? I 
> > > > don't think it'd yield zero.
> > > I'm getting "variable-sized object may not be initialized", so this case 
> > > should not be possible.
> > I'm having a hard time reproducing this either.
> > 
> > 
> > ```
> > struct S {
> >   int a = 3;
> > };
> > S const sarr[2] = {};
> > void definit() {
> >   int i = 1;
> >   clang_analyzer_dump(sarr[i].a); // expected-warning{{test}}
> > }
> > ```
> > 
> > results in a symbolic value, because makeZeroVal returns an empty SVal list 
> > for arrays, records, vectors and complex types. Otherwise it just returns 
> > UnknownVal (for example for not-yet-implemented floats).
> > 
> > Can you think of a case where this would be an issue?
> Yup, sounds reasonable.
Had a look. This indeed looks fine, but for a completely different reason. In 
fact structs don't appear in `getBindingForElement()` because they all go 
through `getBindingForStruct()` instead. Hopefully this does take care of other 
cornercases.

So your test case doesn't even trigger your code to be executed, neither would 
`S s = sarr[i]; clang_analyzer_dump(s.a);`.

Still, as far as i understand, `sarr` here should be zero-initialized, so i 
think the symbolic value can be improved upon, so we might as well add this as 
a FIXME test.


https://reviews.llvm.org/D46823



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-15 Thread Rafael Stahl via Phabricator via cfe-commits
r.stahl added inline comments.



Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())

NoQ wrote:
> NoQ wrote:
> > Would this work correctly if the element is not of an integral or 
> > enumeration type? I think this needs an explicit check.
> What if we have an out-of-bounds access to a variable-length array? I don't 
> think it'd yield zero.
I'm getting "variable-sized object may not be initialized", so this case should 
not be possible.



Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650-1652
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());

r.stahl wrote:
> NoQ wrote:
> > NoQ wrote:
> > > Would this work correctly if the element is not of an integral or 
> > > enumeration type? I think this needs an explicit check.
> > What if we have an out-of-bounds access to a variable-length array? I don't 
> > think it'd yield zero.
> I'm getting "variable-sized object may not be initialized", so this case 
> should not be possible.
I'm having a hard time reproducing this either.


```
struct S {
  int a = 3;
};
S const sarr[2] = {};
void definit() {
  int i = 1;
  clang_analyzer_dump(sarr[i].a); // expected-warning{{test}}
}
```

results in a symbolic value, because makeZeroVal returns an empty SVal list for 
arrays, records, vectors and complex types. Otherwise it just returns 
UnknownVal (for example for not-yet-implemented floats).

Can you think of a case where this would be an issue?


https://reviews.llvm.org/D46823



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-15 Thread Rafael Stahl via Phabricator via cfe-commits
r.stahl updated this revision to Diff 146809.
r.stahl marked 2 inline comments as done.
r.stahl added a comment.

updated test


https://reviews.llvm.org/D46823

Files:
  lib/StaticAnalyzer/Core/RegionStore.cpp
  test/Analysis/initialization.c


Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze 
-analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+  i = 1;
+  clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
+  i = -1;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
+}
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can return
+// an undefined value.
+if (i < 0)
+  return UndefinedVal();
+
+if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+  if (CAT->getSize().sle(i))
+return UndefinedVal();
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());
 
 if (const Expr *ElemInit = InitList->getInit(i))
   if (Optional V = svalBuilder.getConstantVal(ElemInit))
@@ -1715,11 +1724,15 @@
 // Either the record variable or the field has to be const qualified.
 if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
   if (const Expr *Init = VD->getInit())
-if (const auto *InitList = dyn_cast(Init))
-  if (Index < InitList->getNumInits())
+if (const auto *InitList = dyn_cast(Init)) {
+  if (Index < InitList->getNumInits()) {
 if (const Expr *FieldInit = InitList->getInit(Index))
   if (Optional V = svalBuilder.getConstantVal(FieldInit))
 return *V;
+  } else {
+return svalBuilder.makeZeroVal(Ty);
+  }
+}
   }
 
   return getBindingForFieldOrElementCommon(B, R, Ty);


Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+  i = 1;
+  clang_analyzer_eval(parr[i] == 0); // expected-warning{{TRUE}}
+  i = -1;
+  clang_analyzer_eval(parr[i]); // expected-warning{{UNDEFINED}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_eval(sm.a == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(sm.b == 0); // expected-warning{{TRUE}}
+}
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can return
+// an undefined value.
+if (i < 0)
+  return UndefinedVal();
+
+if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))

[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-14 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ added a comment.

Yay thanks!

I think some cornercases would need to be dealt with.




Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())

NoQ wrote:
> Would this work correctly if the element is not of an integral or enumeration 
> type? I think this needs an explicit check.
What if we have an out-of-bounds access to a variable-length array? I don't 
think it'd yield zero.



Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1650-1652
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());

Would this work correctly if the element is not of an integral or enumeration 
type? I think this needs an explicit check.



Comment at: lib/StaticAnalyzer/Core/RegionStore.cpp:1733
+  } else {
+return svalBuilder.makeZeroVal(Ty);
+  }

Same: would this work correctly if the field is not of an integral or 
enumeration type?



Comment at: test/Analysis/initialization.c:3
+
+void clang_analyzer_dump(int);
 

We try to avoid using `dump()` on tests because it makes tests test the dump 
syntax, which isn't the point.

For checking constants, it's easier to do something like 
`clang_analyzer_eval(parr[i] == 2); // expected-warning{{TRUE}}`.

For finding undefined values, you can enable `core.uninitialized` checkers and 
receive warnings when the argument of `clang_analyzer_eval` is an uninitialized 
value. Or just increment the value.


Repository:
  rC Clang

https://reviews.llvm.org/D46823



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D46823: [analyzer] const init: handle non-explicit cases more accurately

2018-05-14 Thread Rafael Stahl via Phabricator via cfe-commits
r.stahl created this revision.
r.stahl added reviewers: NoQ, xazax.hun, george.karpenkov.
Herald added subscribers: cfe-commits, a.sidorin, rnkovacs, szepet.

If the access is out of bounds, return UndefinedVal. If it is missing an 
explicit init, return the implicit zero value it must have.


Repository:
  rC Clang

https://reviews.llvm.org/D46823

Files:
  lib/StaticAnalyzer/Core/RegionStore.cpp
  test/Analysis/initialization.c


Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze 
-analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_dump(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_dump(parr[i]); // expected-warning{{Undefined}}
+  i = 1;
+  clang_analyzer_dump(parr[i]); // expected-warning{{0 S32b}}
+  i = -1;
+  clang_analyzer_dump(parr[i]); // expected-warning{{Undefined}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_dump(sm.a); // expected-warning{{1 S32b}}
+  clang_analyzer_dump(sm.b); // expected-warning{{0 S32b}}
+}
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can return
+// an undefined value.
+if (i < 0)
+  return UndefinedVal();
+
+if (auto CAT = Ctx.getAsConstantArrayType(VD->getType()))
+  if (CAT->getSize().sle(i))
+return UndefinedVal();
+
+// If there is a list, but no init, it must be zero.
+if (i >= InitList->getNumInits())
+  return svalBuilder.makeZeroVal(R->getElementType());
 
 if (const Expr *ElemInit = InitList->getInit(i))
   if (Optional V = svalBuilder.getConstantVal(ElemInit))
@@ -1715,11 +1724,15 @@
 // Either the record variable or the field has to be const qualified.
 if (RecordVarTy.isConstQualified() || Ty.isConstQualified())
   if (const Expr *Init = VD->getInit())
-if (const auto *InitList = dyn_cast(Init))
-  if (Index < InitList->getNumInits())
+if (const auto *InitList = dyn_cast(Init)) {
+  if (Index < InitList->getNumInits()) {
 if (const Expr *FieldInit = InitList->getInit(Index))
   if (Optional V = svalBuilder.getConstantVal(FieldInit))
 return *V;
+  } else {
+return svalBuilder.makeZeroVal(Ty);
+  }
+}
   }
 
   return getBindingForFieldOrElementCommon(B, R, Ty);


Index: test/Analysis/initialization.c
===
--- test/Analysis/initialization.c
+++ test/Analysis/initialization.c
@@ -1,7 +1,28 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// expected-no-diagnostics
+// RUN: %clang_cc1 -triple i386-apple-darwin10 -analyze -analyzer-checker=core.builtin,debug.ExprInspection -verify %s
+
+void clang_analyzer_dump(int);
 
 void initbug() {
   const union { float a; } u = {};
   (void)u.a; // no-crash
 }
+
+int const parr[2] = {1};
+void constarr() {
+  int i = 2;
+  clang_analyzer_dump(parr[i]); // expected-warning{{Undefined}}
+  i = 1;
+  clang_analyzer_dump(parr[i]); // expected-warning{{0 S32b}}
+  i = -1;
+  clang_analyzer_dump(parr[i]); // expected-warning{{Undefined}}
+}
+
+struct SM {
+  int a;
+  int b;
+};
+const struct SM sm = {.a = 1};
+void multinit() {
+  clang_analyzer_dump(sm.a); // expected-warning{{1 S32b}}
+  clang_analyzer_dump(sm.b); // expected-warning{{0 S32b}}
+}
Index: lib/StaticAnalyzer/Core/RegionStore.cpp
===
--- lib/StaticAnalyzer/Core/RegionStore.cpp
+++ lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -1638,9 +1638,18 @@
   // The array index has to be known.
   if (auto CI = R->getIndex().getAs()) {
 int64_t i = CI->getValue().getSExtValue();
-// Return unknown value if index is out of bounds.
-if (i < 0 || i >= InitList->getNumInits())
-  return UnknownVal();
+// If it is known that the index is out of bounds, we can