diff mbox

[C] Disallow subtracting pointers to empty structs (PR c/58346)

Message ID 20140113204839.GF4458@redhat.com
State New
Headers show

Commit Message

Marek Polacek Jan. 13, 2014, 8:48 p.m. UTC
On Mon, Jan 13, 2014 at 05:48:59PM +0100, Marek Polacek wrote:
> The patch will need some tweaking, I realized that e.g. for struct S {
> union {}; }; it doesn't do the right thing...

Done in the patch below.  CCing Jason for the C++ part.  Does this
look sane now?

Regtested/bootstrapped on x86_64.

2014-01-13  Marek Polacek  <polacek@redhat.com>

	PR c/58346
c-family/
	* c-common.c (pointer_to_zero_sized_aggr_p): New function.
	* c-common.h: Declare it.
cp/
	* typeck.c (pointer_diff): Give an error on arithmetic on pointer to
	an empty aggregate.
c/
	* c-typeck.c (pointer_diff): Give an error on arithmetic on pointer to
	an empty aggregate.
testsuite/
	* c-c++-common/pr58346.c: New test.


	Marek

Comments

Jason Merrill Jan. 14, 2014, 2:39 p.m. UTC | #1
The C++ part is OK.

Jason
Florian Weimer Jan. 14, 2014, 5:52 p.m. UTC | #2
On 01/13/2014 09:48 PM, Marek Polacek wrote:
> +bool
> +pointer_to_zero_sized_aggr_p (tree t)
> +{
> +  t = strip_pointer_operator (t);
> +  if (RECORD_OR_UNION_TYPE_P (t)
> +      && TYPE_SIZE (t)
> +      && integer_zerop (TYPE_SIZE (t)))
> +    return true;
> +  return false;
> +}

I think you can just return the value of the condition, there's no need 
for the if statement.
Joseph Myers Jan. 14, 2014, 9:42 p.m. UTC | #3
On Mon, 13 Jan 2014, Marek Polacek wrote:

> +/* Return true if T is a pointer to a zero-sized struct/union.  */
> +
> +bool
> +pointer_to_zero_sized_aggr_p (tree t)
> +{
> +  t = strip_pointer_operator (t);
> +  if (RECORD_OR_UNION_TYPE_P (t)
> +      && TYPE_SIZE (t)
> +      && integer_zerop (TYPE_SIZE (t)))
> +    return true;
> +  return false;

Given that GNU C also allows arrays of constant size 0, shouldn't the 
errors also apply in that case?  (I don't know whether the original bug 
can appear for such arrays, but I'd think the errors should apply to 
anything with constant size 0 - not of course for VLAs where it just so 
happens that the compiler can tell at compile time that the size is always 
0.)
Marek Polacek Jan. 15, 2014, 9:12 a.m. UTC | #4
On Tue, Jan 14, 2014 at 06:52:00PM +0100, Florian Weimer wrote:
> On 01/13/2014 09:48 PM, Marek Polacek wrote:
> >+bool
> >+pointer_to_zero_sized_aggr_p (tree t)
> >+{
> >+  t = strip_pointer_operator (t);
> >+  if (RECORD_OR_UNION_TYPE_P (t)
> >+      && TYPE_SIZE (t)
> >+      && integer_zerop (TYPE_SIZE (t)))
> >+    return true;
> >+  return false;
> >+}
> 
> I think you can just return the value of the condition, there's no
> need for the if statement.

Oops, yeah, forgot to change that.  Will do it in next patch.

	Marek
diff mbox

Patch

--- gcc/c-family/c-common.h.mp	2014-01-13 19:02:22.249870601 +0100
+++ gcc/c-family/c-common.h	2014-01-13 19:04:15.068294390 +0100
@@ -789,6 +789,7 @@  extern bool keyword_is_storage_class_spe
 extern bool keyword_is_type_qualifier (enum rid);
 extern bool keyword_is_decl_specifier (enum rid);
 extern bool cxx_fundamental_alignment_p (unsigned);
+extern bool pointer_to_zero_sized_aggr_p (tree);
 
 #define c_sizeof(LOC, T)  c_sizeof_or_alignof_type (LOC, T, true, false, 1)
 #define c_alignof(LOC, T) c_sizeof_or_alignof_type (LOC, T, false, false, 1)
--- gcc/c-family/c-common.c.mp	2014-01-13 19:01:20.503637616 +0100
+++ gcc/c-family/c-common.c	2014-01-13 19:42:32.805135382 +0100
@@ -11829,4 +11829,17 @@  cxx_fundamental_alignment_p  (unsigned a
 			 TYPE_ALIGN (long_double_type_node)));
 }
 
+/* Return true if T is a pointer to a zero-sized struct/union.  */
+
+bool
+pointer_to_zero_sized_aggr_p (tree t)
+{
+  t = strip_pointer_operator (t);
+  if (RECORD_OR_UNION_TYPE_P (t)
+      && TYPE_SIZE (t)
+      && integer_zerop (TYPE_SIZE (t)))
+    return true;
+  return false;
+}
+
 #include "gt-c-family-c-common.h"
--- gcc/cp/typeck.c.mp	2014-01-13 19:08:12.237244663 +0100
+++ gcc/cp/typeck.c	2014-01-13 19:10:23.350742070 +0100
@@ -5043,6 +5043,14 @@  pointer_diff (tree op0, tree op1, tree p
 	return error_mark_node;
     }
 
+  if (pointer_to_zero_sized_aggr_p (TREE_TYPE (op1)))
+    {
+      if (complain & tf_error)
+	error ("arithmetic on pointer to an empty aggregate");
+      else
+	return error_mark_node;
+    }
+
   op1 = (TYPE_PTROB_P (ptrtype)
 	 ? size_in_bytes (target_type)
 	 : integer_one_node);
--- gcc/c/c-typeck.c.mp	2014-01-13 15:47:01.316105676 +0100
+++ gcc/c/c-typeck.c	2014-01-13 19:58:19.237271626 +0100
@@ -3536,6 +3536,9 @@  pointer_diff (location_t loc, tree op0,
   /* This generates an error if op0 is pointer to incomplete type.  */
   op1 = c_size_in_bytes (target_type);
 
+  if (pointer_to_zero_sized_aggr_p (TREE_TYPE (orig_op1)))
+    error_at (loc, "arithmetic on pointer to an empty aggregate");
+
   /* Divide by the size, in easiest possible way.  */
   result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype,
 			    op0, convert (inttype, op1));
--- gcc/testsuite/c-c++-common/pr58346.c.mp	2014-01-13 15:48:20.011420141 +0100
+++ gcc/testsuite/c-c++-common/pr58346.c	2014-01-13 20:25:17.544582444 +0100
@@ -0,0 +1,24 @@ 
+/* PR c/58346 */
+/* { dg-do compile } */
+
+struct U {
+#ifdef __cplusplus
+  char a[0];
+#endif
+};
+static struct U b[6];
+static struct U **u1, **u2;
+
+int
+foo (struct U *p, struct U *q)
+{
+  return q - p; /* { dg-error "arithmetic on pointer to an empty aggregate" } */
+}
+
+void
+bar (void)
+{
+  __PTRDIFF_TYPE__ d = u1 - u2; /* { dg-error "arithmetic on pointer to an empty aggregate" } */
+  __asm volatile ("" : "+g" (d));
+  foo (&b[0], &b[4]);
+}