[libcxx-commits] [libcxx] 128b213 - [libcxx] [test] Generalize defines for skipping allocation checks

Martin Storsjö via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 10 01:06:58 PDT 2021


Author: Martin Storsjö
Date: 2021-08-10T11:05:00+03:00
New Revision: 128b2136ec62ccfaac8f2b02e87d14f191a154ca

URL: https://github.com/llvm/llvm-project/commit/128b2136ec62ccfaac8f2b02e87d14f191a154ca
DIFF: https://github.com/llvm/llvm-project/commit/128b2136ec62ccfaac8f2b02e87d14f191a154ca.diff

LOG: [libcxx] [test] Generalize defines for skipping allocation checks

This allows waiving the right amount of asserts on Windows and zOS.
This should supersede D107124 and D105910.

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

Added: 
    

Modified: 
    libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
    libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
    libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
    libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp
    libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp
    libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp
    libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
    libcxx/test/support/test_macros.h

Removed: 
    


################################################################################
diff  --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
index d9701a321bcf4..5157161bae872 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp
@@ -194,22 +194,23 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
   // For "char" no allocations will be performed because no conversion is
   // required.
   // On Windows, the append method is more complex and uses intermediate
-  // path objects, which causes extra allocations.
-  // In DLL builds on Windows, the overridden operator new won't pick up
-  // allocations done within the DLL, so the RequireAllocationGuard below
-  // won't necessarily see allocations in the cases where they're expected.
-#ifdef _WIN32
-  bool DisableAllocations = false;
-#else
-  bool DisableAllocations = std::is_same<CharT, char>::value;
+  // path objects, which causes extra allocations. This is checked by comparing
+  // path::value_type with "char" - on Windows, it's wchar_t.
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+  // Only check allocations if we can pick up allocations done within the
+  // library implementation.
+  bool ExpectNoAllocations = std::is_same<CharT, char>::value &&
+                             std::is_same<path::value_type, char>::value;
 #endif
   {
     path LHS(L); PathReserve(LHS, ReserveSize);
     InputIter RHS(R);
     {
-      RequireAllocationGuard  g; // requires 1 or more allocations occur by default
-      if (DisableAllocations) g.requireExactly(0);
-      else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0));
+      RequireAllocationGuard g(0); // require "at least zero" allocations by default
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+      if (ExpectNoAllocations)
+        g.requireExactly(0);
+#endif
       LHS /= RHS;
     }
     assert(PathEq(LHS, E));
@@ -219,9 +220,11 @@ void doAppendSourceAllocTest(AppendOperatorTestcase const& TC)
     InputIter RHS(R);
     InputIter REnd(StrEnd(R));
     {
-      RequireAllocationGuard g;
-      if (DisableAllocations) g.requireExactly(0);
-      else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0));
+      RequireAllocationGuard g(0); // require "at least zero" allocations by default
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+      if (ExpectNoAllocations)
+        g.requireExactly(0);
+#endif
       LHS.append(RHS, REnd);
     }
     assert(PathEq(LHS, E));

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
index c13469fd30d17..cb25c66bf5120 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp
@@ -28,9 +28,8 @@ int main(int, char**) {
   assert(globalMemCounter.checkOutstandingNewEq(0));
   const std::string s("we really really really really really really really "
                       "really really long string so that we allocate");
-  // On windows, the operator new from count_new.h can't override the default
-  // operator for calls within the libc++ DLL.
-  TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkOutstandingNewEq(1)));
+  ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(
+      globalMemCounter.checkOutstandingNewEq(1));
   const fs::path::string_type ps(s.begin(), s.end());
   path p(s);
   {

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
index 221c4c464e6ce..6212e1d706338 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp
@@ -141,17 +141,20 @@ void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
   // For the path native type, no allocations will be performed because no
   // conversion is required.
 
-  // In DLL builds on Windows, the overridden operator new won't pick up
-  // allocations done within the DLL, so the RequireAllocationGuard below
-  // won't necessarily see allocations in the cases where they're expected.
-  bool DisableAllocations = std::is_same<CharT, path::value_type>::value;
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+  // Only check allocations if we can pick up allocations done within the
+  // library implementation.
+  bool ExpectNoAllocations = std::is_same<CharT, path::value_type>::value;
+#endif
   {
     path LHS(L); PathReserve(LHS, ReserveSize);
     InputIter RHS(R);
     {
-      RequireAllocationGuard  g; // requires 1 or more allocations occur by default
-      if (DisableAllocations) g.requireExactly(0);
-      else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0));
+      RequireAllocationGuard g(0); // require "at least zero" allocations by default
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+      if (ExpectNoAllocations)
+        g.requireExactly(0);
+#endif
       LHS += RHS;
     }
     assert(LHS == E);
@@ -161,9 +164,11 @@ void doConcatSourceAllocTest(ConcatOperatorTestcase const& TC)
     InputIter RHS(R);
     InputIter REnd(StrEnd(R));
     {
-      RequireAllocationGuard g;
-      if (DisableAllocations) g.requireExactly(0);
-      else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0));
+      RequireAllocationGuard g(0); // require "at least zero" allocations by default
+#if TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS
+      if (ExpectNoAllocations)
+        g.requireExactly(0);
+#endif
       LHS.concat(RHS, REnd);
     }
     assert(LHS == E);

diff  --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
index f0d324b2f8601..cdf39e33d3fd1 100644
--- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp
@@ -28,9 +28,8 @@ int main(int, char**) {
   assert(globalMemCounter.checkOutstandingNewEq(0));
   const std::string s("we really really really really really really really "
                       "really really long string so that we allocate");
-  // On windows, the operator new from count_new.h can't override the default
-  // operator for calls within the libc++ DLL.
-  TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkOutstandingNewEq(1)));
+  ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(
+      globalMemCounter.checkOutstandingNewEq(1));
   const fs::path::string_type ps(s.begin(), s.end());
   path p(s);
   {

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp
index 038b0e7b7ae0b..ee2f932761f1d 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp
@@ -62,9 +62,9 @@ void* operator new[](std::size_t s, std::align_val_t a) TEST_THROW_SPEC(std::bad
 
 void  operator delete[](void* p, std::align_val_t a) TEST_NOEXCEPT
 {
-    assert(p == Buff);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(p == Buff);
     assert(static_cast<std::size_t>(a) == OverAligned);
-    assert(new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
     --new_called;
 }
 
@@ -74,18 +74,18 @@ int main(int, char**)
         A* ap = new (std::nothrow) A[2];
         assert(ap);
         assert(A_constructed == 2);
-        assert(new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
         delete [] ap;
         assert(A_constructed == 0);
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
     }
     {
         B* bp = new (std::nothrow) B[2];
         assert(bp);
         assert(B_constructed == 2);
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
         delete [] bp;
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
         assert(!B_constructed);
     }
 

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp
index 90785d8dc24d8..dcfc603f5da94 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp
@@ -50,11 +50,11 @@ int main(int, char**)
     DoNotOptimize(ap);
     assert(ap);
     assert(A_constructed == 3);
-    assert(new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
     delete [] ap;
     DoNotOptimize(ap);
     assert(A_constructed == 0);
-    assert(!new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
 
   return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp
index 9058171bbdc3a..384c97beca9b9 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp
@@ -51,11 +51,11 @@ int main(int, char**)
     DoNotOptimize(ap);
     assert(ap);
     assert(A_constructed == 3);
-    assert(new_called == 1);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
     delete [] ap;
     DoNotOptimize(ap);
     assert(A_constructed == 0);
-    assert(new_called == 0);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp
index 7df5663a1c73e..8057e2974987d 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp
@@ -62,9 +62,9 @@ void* operator new(std::size_t s, std::align_val_t a) TEST_THROW_SPEC(std::bad_a
 
 void  operator delete(void* p, std::align_val_t a) TEST_NOEXCEPT
 {
-    assert(p == Buff);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(p == Buff);
     assert(static_cast<std::size_t>(a) == OverAligned);
-    assert(new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
     --new_called;
 }
 
@@ -75,18 +75,18 @@ int main(int, char**)
         A* ap = new (std::nothrow) A;
         assert(ap);
         assert(A_constructed);
-        assert(new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
         delete ap;
         assert(!A_constructed);
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
     }
     {
         B* bp = new (std::nothrow) B;
         assert(bp);
         assert(B_constructed);
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
         delete bp;
-        assert(!new_called);
+        ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
         assert(!B_constructed);
     }
 

diff  --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp
index cf6e5f4586005..4182788d43b88 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp
@@ -50,11 +50,11 @@ int main(int, char**)
     DoNotOptimize(ap);
     assert(ap);
     assert(A_constructed);
-    assert(new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called);
     delete ap;
     DoNotOptimize(ap);
     assert(!A_constructed);
-    assert(!new_called);
+    ASSERT_WITH_OPERATOR_NEW_FALLBACKS(!new_called);
 
   return 0;
 }

diff  --git a/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp
index 0533bb8c20b32..7be7e8d574e6c 100644
--- a/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp
+++ b/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp
@@ -37,9 +37,8 @@ int main(int, char**)
             new std::ctype<char>(new std::ctype<char>::mask[256], true));
         assert(globalMemCounter.checkDeleteArrayCalledEq(0));
     }
-    // On windows, the operator new from count_new.h can't override the default
-    // operator for calls within the libc++ DLL.
-    TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkDeleteArrayCalledEq(1)));
+    ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(
+        globalMemCounter.checkDeleteArrayCalledEq(1));
 
   return 0;
 }

diff  --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
index 6dfe1ceffb19c..b5f38478ca70c 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp
@@ -136,7 +136,7 @@ void test_throwing_new_during_thread_creation() {
     for (int i=0; i <= numAllocs; ++i) {
         throw_one = i;
         f_run = false;
-        TEST_NOT_WIN32_DLL(unsigned old_outstanding = outstanding_new);
+        unsigned old_outstanding = outstanding_new;
         try {
             std::thread t(f);
             assert(i == numAllocs); // Only final iteration will not throw.
@@ -146,9 +146,7 @@ void test_throwing_new_during_thread_creation() {
             assert(i < numAllocs);
             assert(!f_run); // (2.2)
         }
-        // In DLL builds on Windows, the overridden operators new/delete won't
-        // override calls from within the DLL, so this won't match.
-        TEST_NOT_WIN32_DLL(assert(old_outstanding == outstanding_new)); // (2.3)
+        ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(old_outstanding == outstanding_new); // (2.3)
     }
     f_run = false;
     throw_one = 0xFFF;

diff  --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h
index 96c6965ec65d4..cdff591cab548 100644
--- a/libcxx/test/support/test_macros.h
+++ b/libcxx/test/support/test_macros.h
@@ -381,12 +381,43 @@ inline void DoNotOptimize(Tp const& value) {
 #define TEST_NOT_WIN32(...) __VA_ARGS__
 #endif
 
-#if defined(_WIN32) && !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
-#define TEST_NOT_WIN32_DLL(...) ((void)0)
-#define TEST_ONLY_WIN32_DLL(...) __VA_ARGS__
+#if (defined(_WIN32) && !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)) ||   \
+    defined(__MVS__)
+// Macros for waiving cases when we can't count allocations done within
+// the library implementation.
+//
+// On Windows, when libc++ is built as a DLL, references to operator new/delete
+// within the DLL are bound at link time to the operator new/delete within
+// the library; replacing them in the user executable doesn't override the
+// calls within the library.
+//
+// The same goes on IBM zOS.
+#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) ((void)(__VA_ARGS__))
+#define TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 0
+#else
+#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) assert(__VA_ARGS__)
+#define TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 1
+#endif
+
+#if (defined(_WIN32) && !defined(_MSC_VER) &&                                  \
+     !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)) ||                      \
+    defined(__MVS__)
+// Normally, a replaced e.g. 'operator new' ends up used if the user code
+// does a call to e.g. 'operator new[]'; it's enough to replace the base
+// versions and have it override all of them.
+//
+// When the fallback operators are located within the libc++ library and we
+// can't override the calls within it (see above), this fallback mechanism
+// doesn't work either.
+//
+// On Windows, when using the MSVC vcruntime, the operator new/delete fallbacks
+// are linked separately from the libc++ library, linked statically into
+// the end user executable, and these fallbacks work even in DLL configurations.
+// In MinGW configurations when built as a DLL, and on zOS, these fallbacks
+// don't work though.
+#define ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) ((void)(__VA_ARGS__))
 #else
-#define TEST_NOT_WIN32_DLL(...) __VA_ARGS__
-#define TEST_ONLY_WIN32_DLL(...) ((void)0)
+#define ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) assert(__VA_ARGS__)
 #endif
 
 #ifdef _WIN32


        


More information about the libcxx-commits mailing list