diff mbox series

[5/6] detect unterminated const arrays in stpcpy calls (PR 86552)

Message ID 267b54f8-c0c5-0205-d792-747a11567ff6@gmail.com
State New
Headers show
Series improve handling of char arrays with missing nul (PR 86552, 86711, 86714) | expand

Commit Message

Martin Sebor Aug. 13, 2018, 9:28 p.m. UTC
The attached changes implement the detection of past-the-end reads
by stpcpy due to unterminated arguments.

Comments

Jeff Law Aug. 30, 2018, 11:06 p.m. UTC | #1
On 08/13/2018 03:28 PM, Martin Sebor wrote:
> The attached changes implement the detection of past-the-end reads
> by stpcpy due to unterminated arguments.
> 
> 
> gcc-86552-5.diff
> 
> 
> PR tree-optimization/86552 - missing warning for reading past the end of non-string arrays
> 
> gcc/ChangeLog:
> 
> 	* builtins.c (unterminated_array): Handle ARRAY_REF.
> 	(expand_builtin_stpcpy_1): Detect unterminated char arrays.
> 	* builtins.h (unterminated_array): Declare extern.
> 	* gimple-fold.c (gimple_fold_builtin_stpcpy): Detect unterminated
> 	  arrays.
> 	(gimple_fold_builtin_sprintf): Propagate NO_WARNING to transformed
> 	calls.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/warn-stpcpy-no-nul.c: New test.
Same story and resolution as #2, #3 and #4.

Jeff
Jeff Law Sept. 14, 2018, 6:29 p.m. UTC | #2
On 8/13/18 3:28 PM, Martin Sebor wrote:
> The attached changes implement the detection of past-the-end reads
> by stpcpy due to unterminated arguments.
> 
> 
> gcc-86552-5.diff
> 
> PR tree-optimization/86552 - missing warning for reading past the end of non-string arrays
> 
> gcc/ChangeLog:
> 
> 	* builtins.c (unterminated_array): Handle ARRAY_REF.
> 	(expand_builtin_stpcpy_1): Detect unterminated char arrays.
> 	* builtins.h (unterminated_array): Declare extern.
> 	* gimple-fold.c (gimple_fold_builtin_stpcpy): Detect unterminated
> 	  arrays.
> 	(gimple_fold_builtin_sprintf): Propagate NO_WARNING to transformed
> 	calls.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.dg/warn-stpcpy-no-nul.c: New test.
So with this patch I just added initialization for a NONSTR passed down
to c_strlen.  Otherwise it just worked on top of all the recent changes.

I'll install it on the trunk momentarily.

I'll probably stop here today to let the testers run through another
cycle.  What's left of this kit is #4 (sprintf) and #6 (strnlen).

Jeff
diff mbox series

Patch

PR tree-optimization/86552 - missing warning for reading past the end of non-string arrays

gcc/ChangeLog:

	* builtins.c (unterminated_array): Handle ARRAY_REF.
	(expand_builtin_stpcpy_1): Detect unterminated char arrays.
	* builtins.h (unterminated_array): Declare extern.
	* gimple-fold.c (gimple_fold_builtin_stpcpy): Detect unterminated
	  arrays.
	(gimple_fold_builtin_sprintf): Propagate NO_WARNING to transformed
	calls.

gcc/testsuite/ChangeLog:

	* gcc.dg/warn-stpcpy-no-nul.c: New test.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index a77f25c..2f493d3 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -584,7 +584,7 @@  warn_string_no_nul (location_t loc, tree exp, tree fndecl, tree nonstr)
    the declaration of the object of which the array is a member or
    element.  Otherwise return null.  */
 
-static tree
+tree
 unterminated_array (tree exp)
 {
   if (TREE_CODE (exp) == SSA_NAME)
@@ -595,7 +595,10 @@  unterminated_array (tree exp)
 
       tree rhs1 = gimple_assign_rhs1 (stmt);
       tree_code code = gimple_assign_rhs_code (stmt);
-      if (code != POINTER_PLUS_EXPR)
+      if (code == ADDR_EXPR
+	  && TREE_CODE (TREE_OPERAND (rhs1, 0)) == ARRAY_REF)
+	rhs1 = rhs1;
+      else if (code != POINTER_PLUS_EXPR)
 	return NULL_TREE;
 
       exp = rhs1;
@@ -4004,9 +4007,14 @@  expand_builtin_stpcpy_1 (tree exp, rtx target, machine_mode mode)
 	 compile-time, not an expression containing a string.  This is
 	 because the latter will potentially produce pessimized code
 	 when used to produce the return value.  */
-      if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
+      tree nonstr = NULL_TREE;
+      if (!c_getstr (src, NULL, &nonstr)
+	  || !(len = c_strlen (src, 0, &nonstr)))
 	return expand_movstr (dst, src, target, /*endp=*/2);
 
+      if (nonstr && !TREE_NO_WARNING (exp))
+	warn_string_no_nul (EXPR_LOCATION (exp), exp, NULL_TREE, nonstr);
+
       lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
       ret = expand_builtin_mempcpy_args (dst, src, lenp1,
 					 target, exp, /*endp=*/2);
diff --git a/gcc/builtins.h b/gcc/builtins.h
index 73b0b0b..f722dd8 100644
--- a/gcc/builtins.h
+++ b/gcc/builtins.h
@@ -103,6 +103,7 @@  extern bool target_char_cst_p (tree t, char *p);
 
 extern internal_fn associated_internal_fn (tree);
 extern internal_fn replacement_internal_fn (gcall *);
+extern tree unterminated_array (tree);
 extern void warn_string_no_nul (location_t, tree, tree, tree);
 extern tree max_object_size ();
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 3fb8d85..70cb4ef 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -2787,7 +2787,7 @@  gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
   location_t loc = gimple_location (stmt);
   tree dest = gimple_call_arg (stmt, 0);
   tree src = gimple_call_arg (stmt, 1);
-  tree fn, len, lenp1;
+  tree fn, lenp1;
 
   /* If the result is unused, replace stpcpy with strcpy.  */
   if (gimple_call_lhs (stmt) == NULL_TREE)
@@ -2800,10 +2800,25 @@  gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
       return true;
     }
 
-  len = c_strlen (src, 1);
+  /* Set to non-null if ARG refers to an unterminated array.  */
+  tree nonstr;
+  tree len = c_strlen (src, 1, &nonstr);
   if (!len
       || TREE_CODE (len) != INTEGER_CST)
-    return false;
+    {
+      nonstr = unterminated_array (src);
+      if (!nonstr)
+	return false;
+    }
+
+  if (nonstr)
+    {
+      /* Avoid folding calls with unterminated arrays.  */
+      if (!gimple_no_warning_p (stmt))
+	warn_string_no_nul (loc, NULL_TREE, gimple_call_fndecl (stmt), nonstr);
+      gimple_set_no_warning (stmt, true);
+      return false;
+    }
 
   if (optimize_function_for_size_p (cfun)
       /* If length is zero it's small enough.  */
@@ -3066,6 +3081,12 @@  gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
 	 'format' is known to contain no % formats.  */
       gimple_seq stmts = NULL;
       gimple *repl = gimple_build_call (fn, 2, dest, fmt);
+
+      /* Propagate the NO_WARNING bit to avoid issuing the same
+	 warning more than once.  */
+      if (gimple_no_warning_p (stmt))
+	gimple_set_no_warning (repl, true);
+
       gimple_seq_add_stmt_without_update (&stmts, repl);
       if (gimple_call_lhs (stmt))
 	{
@@ -3114,6 +3135,12 @@  gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
       /* Convert sprintf (str1, "%s", str2) into strcpy (str1, str2).  */
       gimple_seq stmts = NULL;
       gimple *repl = gimple_build_call (fn, 2, dest, orig);
+
+      /* Propagate the NO_WARNING bit to avoid issuing the same
+	 warning more than once.  */
+      if (gimple_no_warning_p (stmt))
+	gimple_set_no_warning (repl, true);
+
       gimple_seq_add_stmt_without_update (&stmts, repl);
       if (gimple_call_lhs (stmt))
 	{
diff --git a/gcc/testsuite/gcc.dg/warn-stpcpy-no-nul.c b/gcc/testsuite/gcc.dg/warn-stpcpy-no-nul.c
new file mode 100644
index 0000000..78c4a7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/warn-stpcpy-no-nul.c
@@ -0,0 +1,324 @@ 
+/* PR tree-optimization/86552 - missing warning for reading past the end
+   of non-string arrays
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
+
+extern char* stpcpy (char*, const char*);
+
+const char a[5] = "12345";   /* { dg-message "declared here" } */
+
+int v0 = 0;
+int v1 = 1;
+int v2 = 1;
+int v3 = 1;
+
+void sink (char*, ...);
+
+#define T(str) sink (stpcpy (d, str))
+
+void test_one_dim_array (char *d)
+{
+  T (a);                /* { dg-warning "argument missing terminating nul" }  */
+  T (&a[0]);            /* { dg-warning "nul" }  */
+  T (&a[0] + 1);        /* { dg-warning "nul" }  */
+  T (&a[1]);            /* { dg-warning "nul" }  */
+
+  int i0 = 0;
+  int i1 = i0 + 1;
+
+  T (&a[i0]);           /* { dg-warning "nul" }  */
+  T (&a[i0] + 1);       /* { dg-warning "nul" }  */
+  T (&a[i1]);           /* { dg-warning "nul" }  */
+
+  T (&a[v0]);           /* { dg-warning "nul" }  */
+  T (&a[v0] + 1);       /* { dg-warning "nul" }  */
+  T (&a[v0] + v1);      /* { dg-warning "nul" }  */
+}
+
+const char b[][5] = { /* { dg-message "declared here" } */
+  "12", "123", "1234", "54321"
+};
+
+void test_two_dim_array (char *d)
+{
+  int i0 = 0;
+  int i1 = i0 + 1;
+  int i2 = i1 + 1;
+  int i3 = i2 + 1;
+
+  T (b[0]);
+  T (b[1]);
+  T (b[2]);
+  T (b[3]);             /* { dg-warning "nul" }  */
+  T (b[i0]);
+  T (b[i1]);
+  T (b[i2]);
+  T (b[i3]);            /* { dg-warning "nul" }  */
+  T (b[v0]);
+  T (b[v3]);
+
+  T (&b[2][1]);
+  T (&b[2][1] + 1);
+  T (&b[2][v0]);
+  T (&b[2][1] + v0);
+
+  T (&b[i2][i1]);
+  T (&b[i2][i1] + i1);
+  T (&b[i2][v0]);
+  T (&b[i2][i1] + v0);
+
+  T (&b[3][1]);         /* { dg-warning "nul" }  */
+  T (&b[3][1] + 1);     /* { dg-warning "nul" }  */
+  T (&b[3][v0]);        /* { dg-warning "nul" }  */
+  T (&b[3][1] + v0);    /* { dg-warning "nul" }  */
+  T (&b[3][v0] + v1);   /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (&b[i3][i1]);       /* { dg-warning "nul" }  */
+  T (&b[i3][i1] + i1);  /* { dg-warning "nul" }  */
+  T (&b[i3][v0]);       /* { dg-warning "nul" }  */
+  T (&b[i3][i1] + v0);  /* { dg-warning "nul" }  */
+  T (&b[i3][v0] + v1);  /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? "" : b[0]);
+  T (v0 ? "" : b[1]);
+  T (v0 ? "" : b[2]);
+  T (v0 ? "" : b[3]);               /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? b[0] : "");
+  T (v0 ? b[1] : "");
+  T (v0 ? b[2] : "");
+  T (v0 ? b[3] : "");               /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? "1234" : b[3]);           /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? b[3] : "1234");           /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? a : b[3]);                /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? b[0] : b[2]);
+  T (v0 ? b[2] : b[3]);             /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? b[3] : b[2]);             /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? b[0] : &b[3][0] + 1);     /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? b[1] : &b[3][1] + v0);    /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  /* It's possible to detect the missing nul in the following two
+     expressions but GCC doesn't do it yet.  */
+  T (v0 ? &b[3][1] + v0 : b[2]);    /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? &b[3][v0] : &b[3][v1]);   /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+}
+
+struct A { char a[5], b[5]; };
+
+const struct A s = { "1234", "12345" };
+
+void test_struct_member (char *d)
+{
+  int i0 = 0;
+  int i1 = i0 + 1;
+
+  T (s.a);
+  T (&s.a[0]);
+  T (&s.a[0] + 1);
+  T (&s.a[0] + i0);
+  T (&s.a[1]);
+  T (&s.a[1] + 1);
+  T (&s.a[1] + i0);
+
+  T (&s.a[i0]);
+  T (&s.a[i0] + 1);
+  T (&s.a[i0] + v0);
+  T (&s.a[i1]);
+  T (&s.a[i1] + 1);
+  T (&s.a[i1] + v0);
+
+  T (s.a);
+  T (&s.a[0]);
+  T (&s.a[0] + 1);
+  T (&s.a[0] + v0);
+  T (&s.a[1]);
+  T (&s.a[1] + 1);
+  T (&s.a[1] + v0);
+
+  T (&s.a[i0]);
+  T (&s.a[i0] + 1);
+  T (&s.a[i0] + v0);
+  T (&s.a[i1]);
+  T (&s.a[i1] + 1);
+  T (&s.a[i1] + v0);
+
+  T (&s.a[v0]);
+  T (&s.a[v0] + 1);
+  T (&s.a[v0] + v0);
+  T (&s.a[v1]);
+  T (&s.a[v1] + 1);
+  T (&s.a[v1] + v0);
+
+  T (s.b);              /* { dg-warning "nul" }  */
+  T (&s.b[0]);          /* { dg-warning "nul" }  */
+  T (&s.b[0] + 1);      /* { dg-warning "nul" }  */
+  T (&s.b[0] + i0);     /* { dg-warning "nul" }  */
+  T (&s.b[1]);          /* { dg-warning "nul" }  */
+  T (&s.b[1] + 1);      /* { dg-warning "nul" }  */
+  T (&s.b[1] + i0);     /* { dg-warning "nul" }  */
+
+  T (s.b);              /* { dg-warning "nul" }  */
+  T (&s.b[0]);          /* { dg-warning "nul" }  */
+  T (&s.b[0] + 1);      /* { dg-warning "nul" }  */
+  T (&s.b[0] + v0);     /* { dg-warning "nul" }  */
+  T (&s.b[1]);          /* { dg-warning "nul" }  */
+  T (&s.b[1] + 1);      /* { dg-warning "nul" }  */
+  T (&s.b[1] + v0);     /* { dg-warning "nul" }  */
+
+  T (s.b);              /* { dg-warning "nul" }  */
+  T (&s.b[v0]);         /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (&s.b[v0] + 1);     /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (&s.b[v0] + v0);    /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (&s.b[v1]);         /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (&s.b[v1] + 1);     /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (&s.b[v1] + v0);    /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+}
+
+struct B { struct A a[2]; };
+
+const struct B ba[] = {
+  { { { "123", "12345" }, { "12345", "123" } } },
+  { { { "12345", "123" }, { "123", "12345" } } },
+  { { { "1", "12" },      { "123", "1234" } } },
+  { { { "123", "1234" },  { "12345", "12" } } }
+};
+
+void test_array_of_structs (char *d)
+{
+  T (ba[0].a[0].a);
+  T (&ba[0].a[0].a[0]);
+  T (&ba[0].a[0].a[0] + 1);
+  T (&ba[0].a[0].a[0] + v0);
+  T (&ba[0].a[0].a[1]);
+  T (&ba[0].a[0].a[1] + 1);
+  T (&ba[0].a[0].a[1] + v0);
+
+  T (ba[0].a[0].b);           /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[0]);       /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[0] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[0] + v0);  /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[1]);       /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[1] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[0].a[0].b[1] + v0);  /* { dg-warning "nul" }  */
+
+  T (ba[0].a[1].a);           /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[0]);       /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[1]);       /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[0].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+  T (ba[0].a[1].b);
+  T (&ba[0].a[1].b[0]);
+  T (&ba[0].a[1].b[0] + 1);
+  T (&ba[0].a[1].b[0] + v0);
+  T (&ba[0].a[1].b[1]);
+  T (&ba[0].a[1].b[1] + 1);
+  T (&ba[0].a[1].b[1] + v0);
+
+
+  T (ba[1].a[0].a);           /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[0]);       /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[0] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[0] + v0);  /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[1]);       /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[1] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[1].a[0].a[1] + v0);  /* { dg-warning "nul" }  */
+
+  T (ba[1].a[0].b);
+  T (&ba[1].a[0].b[0]);
+  T (&ba[1].a[0].b[0] + 1);
+  T (&ba[1].a[0].b[0] + v0);
+  T (&ba[1].a[0].b[1]);
+  T (&ba[1].a[0].b[1] + 1);
+  T (&ba[1].a[0].b[1] + v0);
+
+  T (ba[1].a[1].a);
+  T (&ba[1].a[1].a[0]);
+  T (&ba[1].a[1].a[0] + 1);
+  T (&ba[1].a[1].a[0] + v0);
+  T (&ba[1].a[1].a[1]);
+  T (&ba[1].a[1].a[1] + 1);
+  T (&ba[1].a[1].a[1] + v0);
+
+  T (ba[1].a[1].b);           /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[0]);       /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[0] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[0] + v0);  /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[1]);       /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[1] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[1].a[1].b[1] + v0);  /* { dg-warning "nul" }  */
+
+
+  T (ba[2].a[0].a);
+  T (&ba[2].a[0].a[0]);
+  T (&ba[2].a[0].a[0] + 1);
+  T (&ba[2].a[0].a[0] + v0);
+  T (&ba[2].a[0].a[1]);
+  T (&ba[2].a[0].a[1] + 1);
+  T (&ba[2].a[0].a[1] + v0);
+
+  T (ba[2].a[0].b);
+  T (&ba[2].a[0].b[0]);
+  T (&ba[2].a[0].b[0] + 1);
+  T (&ba[2].a[0].b[0] + v0);
+  T (&ba[2].a[0].b[1]);
+  T (&ba[2].a[0].b[1] + 1);
+  T (&ba[2].a[0].b[1] + v0);
+
+  T (ba[2].a[1].a);
+  T (&ba[2].a[1].a[0]);
+  T (&ba[2].a[1].a[0] + 1);
+  T (&ba[2].a[1].a[0] + v0);
+  T (&ba[2].a[1].a[1]);
+  T (&ba[2].a[1].a[1] + 1);
+  T (&ba[2].a[1].a[1] + v0);
+
+
+  T (ba[3].a[0].a);
+  T (&ba[3].a[0].a[0]);
+  T (&ba[3].a[0].a[0] + 1);
+  T (&ba[3].a[0].a[0] + v0);
+  T (&ba[3].a[0].a[1]);
+  T (&ba[3].a[0].a[1] + 1);
+  T (&ba[3].a[0].a[1] + v0);
+
+  T (ba[3].a[0].b);
+  T (&ba[3].a[0].b[0]);
+  T (&ba[3].a[0].b[0] + 1);
+  T (&ba[3].a[0].b[0] + v0);
+  T (&ba[3].a[0].b[1]);
+  T (&ba[3].a[0].b[1] + 1);
+  T (&ba[3].a[0].b[1] + v0);
+
+  T (ba[3].a[1].a);           /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[0]);	      /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[0] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[0] + v0);  /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[1]);	      /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[1] + 1);   /* { dg-warning "nul" }  */
+  T (&ba[3].a[1].a[1] + v0);  /* { dg-warning "nul" }  */
+
+  T (ba[3].a[1].b);
+  T (&ba[3].a[1].b[0]);	
+  T (&ba[3].a[1].b[0] + 1);
+  T (&ba[3].a[1].b[0] + v0);
+  T (&ba[3].a[1].b[1]);	
+  T (&ba[3].a[1].b[1] + 1);
+  T (&ba[3].a[1].b[1] + v0);
+
+
+  T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? ba[0].a[0].a : ba[0].a[0].b);           /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? &ba[0].a[0].a[0] : &ba[3].a[1].a[0]);   /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+  T (v0 ? &ba[3].a[1].a[1] :  ba[0].a[0].a);      /* { dg-warning "nul" "bug ???" { xfail *-*-* } }  */
+
+  T (v0 ? ba[0].a[0].a : ba[0].a[1].b);
+  T (v0 ? ba[0].a[1].b : ba[0].a[0].a);
+}
+
+/* { dg-prune-output " reading \[1-9\]\[0-9\]? bytes from a region " } */