mirror of
https://github.com/microsoft/GSL.git
synced 2024-11-03 17:56:43 -05:00
Enable usage of gsl::narrow with exceptions disabled (#640)
* Enable usage of gsl::narrow with exceptions disabled This solution uses the approach of boost::asio to enabling usage of the library in environments where exception usage is either prohibited or not feasible (due to code size constraints). A function template gsl::throw_exception has been added, which in a normal environment just throws the exception. However, when GSL_TERMINATE_ON_CONTRACT_VIOLATION is defined the function is only declared by gsl and the definition of this function template must be supplied by the library's user. Closes: #468 Signed-off-by: Damian Jarek <damian.jarek93@gmail.com> Addition: - understand STL no exception macro - use function static variable to set termination handler in kernel mode - add compile-only tests for no-exception mode * added termination tests and fixed bugs * disabled warning C4577 for msvc 2015
This commit is contained in:
parent
c6bf25a5f6
commit
d846fe50a3
@ -20,6 +20,14 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <stdexcept> // for logic_error
|
#include <stdexcept> // for logic_error
|
||||||
|
|
||||||
|
//
|
||||||
|
// Temporary until MSVC STL supports no-exceptions mode.
|
||||||
|
// Currently terminate is a no-op in this mode, so we add termination behavior back
|
||||||
|
//
|
||||||
|
#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
|
||||||
|
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// There are three configuration options for this GSL implementation's behavior
|
// There are three configuration options for this GSL implementation's behavior
|
||||||
// when pre/post conditions on the GSL types are violated:
|
// when pre/post conditions on the GSL types are violated:
|
||||||
@ -68,18 +76,62 @@ struct fail_fast : public std::logic_error
|
|||||||
{
|
{
|
||||||
explicit fail_fast(char const* const message) : std::logic_error(message) {}
|
explicit fail_fast(char const* const message) : std::logic_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||||
|
|
||||||
|
typedef void (*terminate_handler)();
|
||||||
|
|
||||||
|
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
|
||||||
|
{
|
||||||
|
static terminate_handler handler = &abort;
|
||||||
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[[noreturn]] inline void terminate() noexcept
|
||||||
|
{
|
||||||
|
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
|
||||||
|
(*gsl::details::get_terminate_handler())();
|
||||||
|
#else
|
||||||
|
std::terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
template <typename Exception>
|
||||||
|
[[noreturn]] void throw_exception(Exception&&)
|
||||||
|
{
|
||||||
|
gsl::details::terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
template <typename Exception>
|
||||||
|
[[noreturn]] void throw_exception(Exception&& exception)
|
||||||
|
{
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace gsl
|
||||||
|
|
||||||
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
#define GSL_CONTRACT_CHECK(type, cond) \
|
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||||
(GSL_LIKELY(cond) ? static_cast<void>(0) \
|
(GSL_LIKELY(cond) ? static_cast<void>(0) \
|
||||||
: throw gsl::fail_fast("GSL: " type " failure at " __FILE__ \
|
: gsl::details::throw_exception(gsl::fail_fast( \
|
||||||
": " GSL_STRINGIFY(__LINE__)))
|
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
|
||||||
|
|
||||||
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
#define GSL_CONTRACT_CHECK(type, cond) (GSL_LIKELY(cond) ? static_cast<void>(0) : std::terminate())
|
#define GSL_CONTRACT_CHECK(type, cond) \
|
||||||
|
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
|
||||||
|
|
||||||
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
|
||||||
|
|
||||||
|
@ -110,9 +110,9 @@ template <class T, class U>
|
|||||||
T narrow(U u)
|
T narrow(U u)
|
||||||
{
|
{
|
||||||
T t = narrow_cast<T>(u);
|
T t = narrow_cast<T>(u);
|
||||||
if (static_cast<U>(t) != u) throw narrowing_error();
|
if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error());
|
||||||
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
|
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
|
||||||
throw narrowing_error();
|
gsl::details::throw_exception(narrowing_error());
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,3 +101,64 @@ add_gsl_test(utils_tests)
|
|||||||
add_gsl_test(owner_tests)
|
add_gsl_test(owner_tests)
|
||||||
add_gsl_test(byte_tests)
|
add_gsl_test(byte_tests)
|
||||||
add_gsl_test(algorithm_tests)
|
add_gsl_test(algorithm_tests)
|
||||||
|
|
||||||
|
|
||||||
|
# No exception tests
|
||||||
|
|
||||||
|
foreach(flag_var
|
||||||
|
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||||
|
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||||
|
STRING (REGEX REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}")
|
||||||
|
endforeach(flag_var)
|
||||||
|
|
||||||
|
# this interface adds compile options to how the tests are run
|
||||||
|
# please try to keep entries ordered =)
|
||||||
|
add_library(gsl_tests_config_noexcept INTERFACE)
|
||||||
|
target_compile_options(gsl_tests_config_noexcept INTERFACE
|
||||||
|
$<$<CXX_COMPILER_ID:MSVC>:
|
||||||
|
/D_HAS_EXCEPTIONS=0
|
||||||
|
/wd4702
|
||||||
|
/wd4577
|
||||||
|
/W4
|
||||||
|
/WX
|
||||||
|
>
|
||||||
|
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:
|
||||||
|
-fno-strict-aliasing
|
||||||
|
-fno-exceptions
|
||||||
|
-Wall
|
||||||
|
-Wcast-align
|
||||||
|
-Wconversion
|
||||||
|
-Wctor-dtor-privacy
|
||||||
|
-Werror
|
||||||
|
-Wextra
|
||||||
|
-Wno-missing-braces
|
||||||
|
-Wnon-virtual-dtor
|
||||||
|
-Wold-style-cast
|
||||||
|
-Woverloaded-virtual
|
||||||
|
-Wpedantic
|
||||||
|
-Wshadow
|
||||||
|
-Wsign-conversion
|
||||||
|
>
|
||||||
|
)
|
||||||
|
|
||||||
|
# set definitions for tests
|
||||||
|
target_compile_definitions(gsl_tests_config_noexcept INTERFACE
|
||||||
|
GSL_TERMINATE_ON_CONTRACT_VIOLATION
|
||||||
|
)
|
||||||
|
|
||||||
|
function(add_gsl_test_noexcept name)
|
||||||
|
add_executable(${name} ${name}.cpp)
|
||||||
|
target_link_libraries(${name}
|
||||||
|
GSL
|
||||||
|
gsl_tests_config_noexcept
|
||||||
|
)
|
||||||
|
add_test(
|
||||||
|
${name}
|
||||||
|
${name}
|
||||||
|
)
|
||||||
|
# group all tests under GSL_tests_noexcept
|
||||||
|
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_gsl_test_noexcept(no_exception_throw_tests)
|
||||||
|
add_gsl_test_noexcept(no_exception_ensure_tests)
|
||||||
|
53
tests/no_exception_ensure_tests.cpp
Normal file
53
tests/no_exception_ensure_tests.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cstdlib> // for std::exit
|
||||||
|
#include <gsl/span> // for span
|
||||||
|
|
||||||
|
int operator_subscript_no_throw()
|
||||||
|
{
|
||||||
|
int arr[10];
|
||||||
|
gsl::span<int> sp { arr };
|
||||||
|
return sp[11];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void test_terminate()
|
||||||
|
{
|
||||||
|
std::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_termination_handler()
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
auto& handler = gsl::details::get_terminate_handler();
|
||||||
|
handler = &test_terminate;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
std::set_terminate(test_terminate);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
setup_termination_handler();
|
||||||
|
operator_subscript_no_throw();
|
||||||
|
return -1;
|
||||||
|
}
|
51
tests/no_exception_throw_tests.cpp
Normal file
51
tests/no_exception_throw_tests.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
//
|
||||||
|
// This code is licensed under the MIT License (MIT).
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <cstdlib> // for std::exit
|
||||||
|
#include <gsl/gsl_util> // for narrow
|
||||||
|
|
||||||
|
int narrow_no_throw()
|
||||||
|
{
|
||||||
|
long long bigNumber = 0x0fffffffffffffff;
|
||||||
|
return gsl::narrow<int>(bigNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_terminate()
|
||||||
|
{
|
||||||
|
std::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_termination_handler()
|
||||||
|
{
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
auto& handler = gsl::details::get_terminate_handler();
|
||||||
|
handler = &test_terminate;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
std::set_terminate(test_terminate);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
setup_termination_handler();
|
||||||
|
narrow_no_throw();
|
||||||
|
return -1;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user