CaseyCarter created this revision. CaseyCarter added reviewers: mclow.lists, EricWF.
Drive-by: - Fix potential race between check and update of `throw_one` in operator new - Fix latent bug in operator delete, which shouldn't decrement `outstanding_new` when passed a null pointer - Specifically catch the expected `bad_alloc` in `main` instead of `...` https://reviews.llvm.org/D50860 Files: test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp Index: test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp =================================================================== --- test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp +++ test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp @@ -31,17 +31,19 @@ void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) { - if (throw_one == 0) - TEST_THROW(std::bad_alloc()); - --throw_one; + unsigned expected = throw_one; + do { + if (expected == 0) TEST_THROW(std::bad_alloc()); + } while (!throw_one.compare_exchange_weak(expected, expected - 1)); ++outstanding_new; void* ret = std::malloc(s); if (!ret) std::abort(); // placate MSVC's unchecked malloc warning return ret; } void operator delete(void* p) TEST_NOEXCEPT { + if (!p) return; --outstanding_new; std::free(p); } @@ -116,14 +118,16 @@ // 2.3 Check that no memory allocated by the creation of the thread is leaked. // 3 Finally check that a thread runs successfully if we throw after 'N+1' // allocations. +int numAllocs; + void test_throwing_new_during_thread_creation() { #ifndef TEST_HAS_NO_EXCEPTIONS throw_one = 0xFFF; { std::thread t(f); t.join(); } - const int numAllocs = 0xFFF - throw_one; + numAllocs = 0xFFF - throw_one; // i <= numAllocs means the last iteration is expected not to throw. for (int i=0; i <= numAllocs; ++i) { throw_one = i; @@ -164,16 +168,16 @@ } G::op_run = false; #ifndef TEST_HAS_NO_EXCEPTIONS - { + if (numAllocs > 0) { try { throw_one = 0; assert(G::n_alive == 0); assert(!G::op_run); std::thread t((G())); assert(false); } - catch (...) + catch (std::bad_alloc const&) { throw_one = 0xFFFF; assert(G::n_alive == 0);
Index: test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp =================================================================== --- test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp +++ test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp @@ -31,17 +31,19 @@ void* operator new(std::size_t s) TEST_THROW_SPEC(std::bad_alloc) { - if (throw_one == 0) - TEST_THROW(std::bad_alloc()); - --throw_one; + unsigned expected = throw_one; + do { + if (expected == 0) TEST_THROW(std::bad_alloc()); + } while (!throw_one.compare_exchange_weak(expected, expected - 1)); ++outstanding_new; void* ret = std::malloc(s); if (!ret) std::abort(); // placate MSVC's unchecked malloc warning return ret; } void operator delete(void* p) TEST_NOEXCEPT { + if (!p) return; --outstanding_new; std::free(p); } @@ -116,14 +118,16 @@ // 2.3 Check that no memory allocated by the creation of the thread is leaked. // 3 Finally check that a thread runs successfully if we throw after 'N+1' // allocations. +int numAllocs; + void test_throwing_new_during_thread_creation() { #ifndef TEST_HAS_NO_EXCEPTIONS throw_one = 0xFFF; { std::thread t(f); t.join(); } - const int numAllocs = 0xFFF - throw_one; + numAllocs = 0xFFF - throw_one; // i <= numAllocs means the last iteration is expected not to throw. for (int i=0; i <= numAllocs; ++i) { throw_one = i; @@ -164,16 +168,16 @@ } G::op_run = false; #ifndef TEST_HAS_NO_EXCEPTIONS - { + if (numAllocs > 0) { try { throw_one = 0; assert(G::n_alive == 0); assert(!G::op_run); std::thread t((G())); assert(false); } - catch (...) + catch (std::bad_alloc const&) { throw_one = 0xFFFF; assert(G::n_alive == 0);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits