2014-10-15  Yury Gribov  <y.gribov@samsung.com>

	Backport from mainline
	2014-08-18  Yury Gribov  <y.gribov@samsung.com>

	PR sanitizer/62089

	* asan.c (instrument_derefs): Fix bitfield check.

	* c-c++-common/asan/pr62089.c: New test.
	* c-c++-common/asan/bitfield-1.c: New test.
	* c-c++-common/asan/bitfield-2.c: New test.
	* c-c++-common/asan/bitfield-3.c: New test.
	* c-c++-common/asan/bitfield-4.c: New test.

diff --git a/gcc/asan.c b/gcc/asan.c
index f55b024..e445470 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1688,21 +1688,19 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
   int volatilep = 0, unsignedp = 0;
   tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset,
 				    &mode, &unsignedp, &volatilep, false);
-  if (((size_in_bytes & (size_in_bytes - 1)) == 0
-       && (bitpos % (size_in_bytes * BITS_PER_UNIT)))
-      || bitsize != size_in_bytes * BITS_PER_UNIT)
+
+  if (TREE_CODE (t) == COMPONENT_REF
+      && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
     {
-      if (TREE_CODE (t) == COMPONENT_REF
-	  && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
-	{
-	  tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
-	  instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
-					   TREE_OPERAND (t, 0), repr,
-					   NULL_TREE), location, is_store);
-	}
+      tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
+      instrument_derefs (iter, build3 (COMPONENT_REF, TREE_TYPE (repr),
+				       TREE_OPERAND (t, 0), repr,
+				       NULL_TREE), location, is_store);
       return;
     }
-  if (bitpos % BITS_PER_UNIT)
+
+  if (bitpos % BITS_PER_UNIT
+      || bitsize != size_in_bytes * BITS_PER_UNIT)
     return;
 
   if (TREE_CODE (inner) == VAR_DECL
diff --git a/gcc/testsuite/c-c++-common/asan/bitfield-1.c b/gcc/testsuite/c-c++-common/asan/bitfield-1.c
new file mode 100644
index 0000000..b3f300c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/bitfield-1.c
@@ -0,0 +1,25 @@
+/* Check that Asan correctly instruments bitfields with non-round size.  */
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+struct A
+{
+  char base;
+  int : 4;
+  long x : 7;
+};
+
+int __attribute__ ((noinline, noclone))
+f (void *p) {
+  return ((struct A *)p)->x;
+}
+
+int
+main ()
+{
+  char a = 0;
+  return f (&a);
+}
+
+/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow" } */
diff --git a/gcc/testsuite/c-c++-common/asan/bitfield-2.c b/gcc/testsuite/c-c++-common/asan/bitfield-2.c
new file mode 100644
index 0000000..8ab0f80
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/bitfield-2.c
@@ -0,0 +1,25 @@
+/* Check that Asan correctly instruments bitfields with non-round offset.  */
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+struct A
+{
+  char base;
+  int : 7;
+  int x : 8;
+};
+
+int __attribute__ ((noinline, noclone))
+f (void *p) {
+  return ((struct A *)p)->x;
+}
+
+int
+main ()
+{
+  char a = 0;
+  return f (&a);
+}
+
+/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow" } */
diff --git a/gcc/testsuite/c-c++-common/asan/bitfield-3.c b/gcc/testsuite/c-c++-common/asan/bitfield-3.c
new file mode 100644
index 0000000..c590778
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/bitfield-3.c
@@ -0,0 +1,25 @@
+/* Check that Asan correctly instruments bitfields with round offset.  */
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+struct A
+{
+  char base;
+  int : 8;
+  int x : 8;
+};
+
+int __attribute__ ((noinline, noclone))
+f (void *p) {
+  return ((struct A *)p)->x;
+}
+
+int
+main ()
+{
+  char a = 0;
+  return f (&a);
+}
+
+/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow" } */
diff --git a/gcc/testsuite/c-c++-common/asan/bitfield-4.c b/gcc/testsuite/c-c++-common/asan/bitfield-4.c
new file mode 100644
index 0000000..94de9a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/bitfield-4.c
@@ -0,0 +1,25 @@
+/* Check that Asan correctly instruments bitfields with round offset.  */
+
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+struct A
+{
+  char base;
+  int : 0;
+  int x : 8;
+};
+
+int __attribute__ ((noinline, noclone))
+f (void *p) {
+  return ((struct A *)p)->x;
+}
+
+int
+main ()
+{
+  char a = 0;
+  return f (&a);
+}
+
+/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow" } */
diff --git a/gcc/testsuite/c-c++-common/asan/pr62089.c b/gcc/testsuite/c-c++-common/asan/pr62089.c
new file mode 100644
index 0000000..6c25ea4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/asan/pr62089.c
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-shouldfail "asan" } */
+
+#ifndef __cplusplus
+#define bool unsigned char
+#endif
+
+#include <sanitizer/asan_interface.h>
+
+struct vfsmount {};
+struct dentry {};
+
+struct path {
+  struct vfsmount *mnt;
+  struct dentry *dentry;
+};
+
+struct fs_struct {
+  int users;
+  int lock;
+  int seq;
+  int umask;
+  int in_exec;
+  struct path root, pwd;
+};
+
+void __attribute__((noinline, noclone))
+copy_fs_struct(struct fs_struct *a, struct fs_struct *b) {
+  a->root = b->root;
+}
+
+struct fs_struct a, b;
+
+int
+main () {
+  __asan_poison_memory_region (&a.root, sizeof (a.root));
+  copy_fs_struct (&a, &b);
+  return 0;
+}
+
+/* { dg-output "ERROR: AddressSanitizer: use-after-poison" } */
