[PATCH] Fix to PR5683 - issue diagnostic for pointer subtraction with type of size zero.

Serge Pavlov sepavloff at gmail.com
Mon Apr 8 10:18:05 PDT 2013


  Patch updated

  The patch is reworked according to the recommendations. Error is changed to warning,
  message text is also changed.

  If pointee has zero size, it doesn't mean that it is empty structre. Pointers to
  void, labels and VLA's also report zero size for their pointees. However empty
  unions were not handled propely in the first variant of the patch, this version
  fixes it.

Hi rsmith,

http://llvm-reviews.chandlerc.com/D637

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D637?vs=1541&id=1547#toc

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ExprConstant.cpp
  lib/Sema/SemaExpr.cpp
  test/Sema/empty1.c

Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -3971,6 +3971,9 @@
 def warn_offsetof_non_standardlayout_type : ExtWarn<
   "offset of on non-standard-layout type %0">, InGroup<InvalidOffsetof>;
 def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">;
+def warn_sub_ptr_zero_size_types : Warning<
+  "subtraction of pointers to type %0 with zero size has undefined behavior">,
+  InGroup<PointerArith>;
 
 def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -5003,6 +5003,12 @@
         if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
           return false;
 
+        // Empty struct or union in C has size 0 (GCC extension). Meaning of
+        // pointer difference in such case is unspecified, so set ElementSize
+        // to 1 to avoid division by zero.
+        if (ElementSize.isZero())
+            ElementSize = CharUnits::One();
+
         // FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,
         // and produce incorrect results when it overflows. Such behavior
         // appears to be non-conforming, but is common, so perhaps we should
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -6728,6 +6728,17 @@
           diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
           return QualType();
         }
+
+        // If pointee type is a structure or union of zero size (GCC extension),
+        // the subtraction does not make sense.
+        CharUnits ElementSize = Context.getTypeSizeInChars(rpointee);
+        if (ElementSize.isZero() &&
+            (rpointee.getTypePtr()->isStructureType() ||
+             rpointee.getTypePtr()->isUnionType())) {
+            Diag(Loc,diag::warn_sub_ptr_zero_size_types)
+                << lpointee.getUnqualifiedType()
+                << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+        }
       }
 
       if (!checkArithmeticBinOpPointerOperands(*this, Loc,
Index: test/Sema/empty1.c
===================================================================
--- /dev/null
+++ test/Sema/empty1.c
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify
+
+struct empty {};
+struct empty_2 {};
+union  empty_u {};
+
+struct empty* func_1p (struct empty* x) {
+  return x - 5;
+}
+
+int func_1 () {
+  struct empty v[1];
+  return v - v;  // expected-warning {{subtraction of pointers to type 'struct empty' with zero size has undefined behavior}}
+}
+
+int func_2 (struct empty* x) {
+  return 1 + x - x;  // expected-warning {{subtraction of pointers to type 'struct empty' with zero size has undefined behavior}}
+}
+
+int func_3 (struct empty* x, struct empty* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct empty' with zero size has undefined behavior}}
+}
+
+int func_4 (struct empty* x, const struct empty* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct empty' with zero size has undefined behavior}}
+}
+
+int func_5 (volatile struct empty* x, const struct empty* y) {
+  return x - y;  // expected-warning {{subtraction of pointers to type 'struct empty' with zero size has undefined behavior}}
+}
+
+int func_6 (struct empty* x, struct empty_2* y) {
+  return x - y;  // expected-error {{'struct empty *' and 'struct empty_2 *' are not pointers to compatible types}}
+}
+
+int func_7 () {
+  union empty_u v[1];
+  return v - v;  // expected-warning {{subtraction of pointers to type 'union empty_u' with zero size has undefined behavior}}
+}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D637.2.patch
Type: text/x-patch
Size: 3967 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130408/82bc18b4/attachment.bin>


More information about the cfe-commits mailing list