From 52286a8b458d66b2471211d83576e0c240946e57 Mon Sep 17 00:00:00 2001 From: Christopher Dykes Date: Tue, 9 Aug 2016 17:00:14 -0700 Subject: [PATCH] Add a utility for disabling some CRT assertions in debug mode Summary: See the comment on `msvcReturnInvalidParams` for more info on the issue. This also adds a use of it to TestUtilTest. Reviewed By: yfeldblum Differential Revision: D3691526 fbshipit-source-id: f0f596e9b4c830e1d31de01926162636757329e8 --- folly/experimental/TestUtil.cpp | 30 ++++++++++++++++++++++++ folly/experimental/TestUtil.h | 28 ++++++++++++++++++++++ folly/experimental/test/TestUtilTest.cpp | 16 +++++++------ 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/folly/experimental/TestUtil.cpp b/folly/experimental/TestUtil.cpp index 96572114..138be1a6 100644 --- a/folly/experimental/TestUtil.cpp +++ b/folly/experimental/TestUtil.cpp @@ -30,6 +30,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + namespace folly { namespace test { @@ -128,6 +132,32 @@ ChangeToTempDir::~ChangeToTempDir() { namespace detail { +SavedState disableInvalidParameters() { +#ifdef _WIN32 + SavedState ret; + ret.previousThreadLocalHandler = _set_thread_local_invalid_parameter_handler( + [](const wchar_t*, + const wchar_t*, + const wchar_t*, + unsigned int, + uintptr_t) {}); + ret.previousCrtReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); + return ret; +#else + return SavedState(); +#endif +} + +#ifdef _WIN32 +void enableInvalidParameters(SavedState state) { + _set_thread_local_invalid_parameter_handler( + (_invalid_parameter_handler)state.previousThreadLocalHandler); + _CrtSetReportMode(_CRT_ASSERT, state.previousCrtReportMode); +} +#else +void enableInvalidParameters(SavedState) {} +#endif + bool hasPCREPatternMatch(StringPiece pattern, StringPiece target) { return boost::regex_match( target.begin(), diff --git a/folly/experimental/TestUtil.h b/folly/experimental/TestUtil.h index 5b4112fe..828ca1fd 100644 --- a/folly/experimental/TestUtil.h +++ b/folly/experimental/TestUtil.h @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace folly { @@ -118,6 +119,33 @@ private: TemporaryDirectory dir_; }; +namespace detail { +struct SavedState { + void* previousThreadLocalHandler; + int previousCrtReportMode; +}; +SavedState disableInvalidParameters(); +void enableInvalidParameters(SavedState state); +} + +// Ok, so fun fact: The CRT on windows will actually abort +// on certain failed parameter validation checks in debug +// mode rather than simply returning -1 as it does in release +// mode. We can however, ensure consistent behavior by +// registering our own thread-local invalid parameter handler +// for the duration of the call, and just have that handler +// immediately return. We also have to disable CRT asertion +// alerts for the duration of the call, otherwise we get +// the abort-retry-ignore window. +template +auto msvcSuppressAbortOnInvalidParams(Func func) -> decltype(func()) { + auto savedState = detail::disableInvalidParameters(); + SCOPE_EXIT { + detail::enableInvalidParameters(savedState); + }; + return func(); +} + /** * Easy PCRE regex matching. Note that pattern must match the ENTIRE target, * so use .* at the start and end of the pattern, as appropriate. See diff --git a/folly/experimental/test/TestUtilTest.cpp b/folly/experimental/test/TestUtilTest.cpp index 8c5329a7..3110f6fa 100644 --- a/folly/experimental/test/TestUtilTest.cpp +++ b/folly/experimental/test/TestUtilTest.cpp @@ -45,13 +45,15 @@ TEST(TemporaryFile, Simple) { EXPECT_EQ(1, r); } - // The file must have been closed. This assumes that no other thread - // has opened another file in the meanwhile, which is a sane assumption - // to make in this test. - ssize_t r = write(fd, &c, 1); - int savedErrno = errno; - EXPECT_EQ(-1, r); - EXPECT_EQ(EBADF, savedErrno); + msvcSuppressAbortOnInvalidParams([&] { + // The file must have been closed. This assumes that no other thread + // has opened another file in the meanwhile, which is a sane assumption + // to make in this test. + ssize_t r = write(fd, &c, 1); + int savedErrno = errno; + EXPECT_EQ(-1, r); + EXPECT_EQ(EBADF, savedErrno); + }); } TEST(TemporaryFile, Prefix) { -- 2.34.1