forked from OSchip/llvm-project
[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
This commit is contained in:
parent
81f057c253
commit
128b2136ec
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 TEST_NOT_WIN32_DLL(...) __VA_ARGS__
|
||||
#define TEST_ONLY_WIN32_DLL(...) ((void)0)
|
||||
#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 ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) assert(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
Loading…
Reference in New Issue