r343761 - [constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array

Petr Pavlu via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 4 02:25:44 PDT 2018


Author: petr.pavlu
Date: Thu Oct  4 02:25:44 2018
New Revision: 343761

URL: http://llvm.org/viewvc/llvm-project?rev=343761&view=rev
Log:
[constexpr] Fix ICE when memcpy() is given a pointer to an incomplete array

Fix code for constant evaluation of __builtin_memcpy() and
__builtin_memmove() that would attempt to divide by zero when given two
pointers to an incomplete array.

Differential Revision: https://reviews.llvm.org/D51855

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CodeGen/builtin-memfns.c
    cfe/trunk/test/SemaCXX/constexpr-string.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=343761&r1=343760&r2=343761&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu Oct  4 02:25:44 2018
@@ -173,6 +173,9 @@ def note_constexpr_memcpy_type_pun : Not
 def note_constexpr_memcpy_nontrivial : Note<
   "cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
   "non-trivially-copyable type %1">;
+def note_constexpr_memcpy_incomplete_type : Note<
+  "cannot constant evaluate '%select{memcpy|memmove}0' between objects of "
+  "incomplete type %1">;
 def note_constexpr_memcpy_overlap : Note<
   "'%select{memcpy|wmemcpy}0' between overlapping memory regions">;
 def note_constexpr_memcpy_unsupported : Note<

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=343761&r1=343760&r2=343761&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Oct  4 02:25:44 2018
@@ -6239,6 +6239,10 @@ bool PointerExprEvaluator::VisitBuiltinC
       Info.FFDiag(E, diag::note_constexpr_memcpy_type_pun) << Move << SrcT << T;
       return false;
     }
+    if (T->isIncompleteType()) {
+      Info.FFDiag(E, diag::note_constexpr_memcpy_incomplete_type) << Move << T;
+      return false;
+    }
     if (!T.isTriviallyCopyableType(Info.Ctx)) {
       Info.FFDiag(E, diag::note_constexpr_memcpy_nontrivial) << Move << T;
       return false;

Modified: cfe/trunk/test/CodeGen/builtin-memfns.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtin-memfns.c?rev=343761&r1=343760&r2=343761&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/builtin-memfns.c (original)
+++ cfe/trunk/test/CodeGen/builtin-memfns.c Thu Oct  4 02:25:44 2018
@@ -111,3 +111,10 @@ void test11() {
   memcpy(&d, (char *)&e.a, sizeof(e));
 }
 
+// CHECK-LABEL: @test12
+extern char dest_array[];
+extern char src_array[];
+void test12() {
+  // CHECK: call void @llvm.memcpy{{.*}}(
+  memcpy(&dest_array, &dest_array, 2);
+}

Modified: cfe/trunk/test/SemaCXX/constexpr-string.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-string.cpp?rev=343761&r1=343760&r2=343761&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-string.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-string.cpp Thu Oct  4 02:25:44 2018
@@ -387,4 +387,41 @@ namespace MemcpyEtc {
   // designators until we have a long enough matching size, if both designators
   // point to the start of their respective final elements.
   static_assert(test_derived_to_base(2) == 3434); // expected-error {{constant}} expected-note {{in call}}
+
+  // Check that when address-of an array is passed to a tested function the
+  // array can be fully copied.
+  constexpr int test_address_of_const_array_type() {
+    int arr[4] = {1, 2, 3, 4};
+    __builtin_memmove(&arr, &arr, sizeof(arr));
+    return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_const_array_type() == 1234);
+
+  // Check that an incomplete array is rejected.
+  constexpr int test_incomplete_array_type() { // expected-error {{never produces a constant}}
+    extern int arr[];
+    __builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
+    // expected-note at -1 2{{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
+    return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
+
+  // Check that a pointer to an incomplete array is rejected.
+  constexpr int test_address_of_incomplete_array_type() { // expected-error {{never produces a constant}}
+    extern int arr[];
+    __builtin_memmove(&arr, &arr, 4 * sizeof(arr[0]));
+    // expected-note at -1 2{{cannot constant evaluate 'memmove' between objects of incomplete type 'int []'}}
+    return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
+  }
+  static_assert(test_address_of_incomplete_array_type() == 1234); // expected-error {{constant}} expected-note {{in call}}
+
+  // Check that a pointer to an incomplete struct is rejected.
+  constexpr bool test_address_of_incomplete_struct_type() { // expected-error {{never produces a constant}}
+    struct Incomplete;
+    extern Incomplete x, y;
+    __builtin_memcpy(&x, &x, 4);
+    // expected-note at -1 2{{cannot constant evaluate 'memcpy' between objects of incomplete type 'Incomplete'}}
+    return true;
+  }
+  static_assert(test_address_of_incomplete_struct_type()); // expected-error {{constant}} expected-note {{in call}}
 }




More information about the cfe-commits mailing list