Skip to content

Commit d846fe5

Browse files
author
Anna Gringauze
authored
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
1 parent c6bf25a commit d846fe5

File tree

5 files changed

+223
-6
lines changed

5 files changed

+223
-6
lines changed

include/gsl/gsl_assert

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
#include <exception>
2121
#include <stdexcept> // for logic_error
2222

23+
//
24+
// Temporary until MSVC STL supports no-exceptions mode.
25+
// Currently terminate is a no-op in this mode, so we add termination behavior back
26+
//
27+
#if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
28+
#define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
29+
#endif
30+
2331
//
2432
// There are three configuration options for this GSL implementation's behavior
2533
// when pre/post conditions on the GSL types are violated:
@@ -68,18 +76,62 @@ struct fail_fast : public std::logic_error
6876
{
6977
explicit fail_fast(char const* const message) : std::logic_error(message) {}
7078
};
71-
}
79+
80+
namespace details
81+
{
82+
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
83+
84+
typedef void (*terminate_handler)();
85+
86+
inline gsl::details::terminate_handler& get_terminate_handler() noexcept
87+
{
88+
static terminate_handler handler = &abort;
89+
return handler;
90+
}
91+
92+
#endif
93+
94+
[[noreturn]] inline void terminate() noexcept
95+
{
96+
#if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
97+
(*gsl::details::get_terminate_handler())();
98+
#else
99+
std::terminate();
100+
#endif
101+
}
102+
103+
#if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
104+
105+
template <typename Exception>
106+
[[noreturn]] void throw_exception(Exception&&)
107+
{
108+
gsl::details::terminate();
109+
}
110+
111+
#else
112+
113+
template <typename Exception>
114+
[[noreturn]] void throw_exception(Exception&& exception)
115+
{
116+
throw exception;
117+
}
118+
119+
#endif
120+
121+
} // namespace details
122+
} // namespace gsl
72123

73124
#if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
74125

75126
#define GSL_CONTRACT_CHECK(type, cond) \
76127
(GSL_LIKELY(cond) ? static_cast<void>(0) \
77-
: throw gsl::fail_fast("GSL: " type " failure at " __FILE__ \
78-
": " GSL_STRINGIFY(__LINE__)))
128+
: gsl::details::throw_exception(gsl::fail_fast( \
129+
"GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
79130

80131
#elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
81132

82-
#define GSL_CONTRACT_CHECK(type, cond) (GSL_LIKELY(cond) ? static_cast<void>(0) : std::terminate())
133+
#define GSL_CONTRACT_CHECK(type, cond) \
134+
(GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
83135

84136
#elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
85137

include/gsl/gsl_util

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,9 @@ template <class T, class U>
110110
T narrow(U u)
111111
{
112112
T t = narrow_cast<T>(u);
113-
if (static_cast<U>(t) != u) throw narrowing_error();
113+
if (static_cast<U>(t) != u) gsl::details::throw_exception(narrowing_error());
114114
if (!details::is_same_signedness<T, U>::value && ((t < T{}) != (u < U{})))
115-
throw narrowing_error();
115+
gsl::details::throw_exception(narrowing_error());
116116
return t;
117117
}
118118

tests/CMakeLists.txt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,64 @@ add_gsl_test(utils_tests)
101101
add_gsl_test(owner_tests)
102102
add_gsl_test(byte_tests)
103103
add_gsl_test(algorithm_tests)
104+
105+
106+
# No exception tests
107+
108+
foreach(flag_var
109+
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
110+
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
111+
STRING (REGEX REPLACE "/EHsc" "" ${flag_var} "${${flag_var}}")
112+
endforeach(flag_var)
113+
114+
# this interface adds compile options to how the tests are run
115+
# please try to keep entries ordered =)
116+
add_library(gsl_tests_config_noexcept INTERFACE)
117+
target_compile_options(gsl_tests_config_noexcept INTERFACE
118+
$<$<CXX_COMPILER_ID:MSVC>:
119+
/D_HAS_EXCEPTIONS=0
120+
/wd4702
121+
/wd4577
122+
/W4
123+
/WX
124+
>
125+
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:
126+
-fno-strict-aliasing
127+
-fno-exceptions
128+
-Wall
129+
-Wcast-align
130+
-Wconversion
131+
-Wctor-dtor-privacy
132+
-Werror
133+
-Wextra
134+
-Wno-missing-braces
135+
-Wnon-virtual-dtor
136+
-Wold-style-cast
137+
-Woverloaded-virtual
138+
-Wpedantic
139+
-Wshadow
140+
-Wsign-conversion
141+
>
142+
)
143+
144+
# set definitions for tests
145+
target_compile_definitions(gsl_tests_config_noexcept INTERFACE
146+
GSL_TERMINATE_ON_CONTRACT_VIOLATION
147+
)
148+
149+
function(add_gsl_test_noexcept name)
150+
add_executable(${name} ${name}.cpp)
151+
target_link_libraries(${name}
152+
GSL
153+
gsl_tests_config_noexcept
154+
)
155+
add_test(
156+
${name}
157+
${name}
158+
)
159+
# group all tests under GSL_tests_noexcept
160+
set_property(TARGET ${name} PROPERTY FOLDER "GSL_tests_noexcept")
161+
endfunction()
162+
163+
add_gsl_test_noexcept(no_exception_throw_tests)
164+
add_gsl_test_noexcept(no_exception_ensure_tests)
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4+
//
5+
// This code is licensed under the MIT License (MIT).
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13+
// THE SOFTWARE.
14+
//
15+
///////////////////////////////////////////////////////////////////////////////
16+
17+
#include <cstdlib> // for std::exit
18+
#include <gsl/span> // for span
19+
20+
int operator_subscript_no_throw()
21+
{
22+
int arr[10];
23+
gsl::span<int> sp { arr };
24+
return sp[11];
25+
}
26+
27+
28+
void test_terminate()
29+
{
30+
std::exit(0);
31+
}
32+
33+
void setup_termination_handler()
34+
{
35+
#if defined(_MSC_VER)
36+
37+
auto& handler = gsl::details::get_terminate_handler();
38+
handler = &test_terminate;
39+
40+
#else
41+
42+
std::set_terminate(test_terminate);
43+
44+
#endif
45+
}
46+
47+
48+
int main()
49+
{
50+
setup_termination_handler();
51+
operator_subscript_no_throw();
52+
return -1;
53+
}

tests/no_exception_throw_tests.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4+
//
5+
// This code is licensed under the MIT License (MIT).
6+
//
7+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13+
// THE SOFTWARE.
14+
//
15+
///////////////////////////////////////////////////////////////////////////////
16+
17+
#include <cstdlib> // for std::exit
18+
#include <gsl/gsl_util> // for narrow
19+
20+
int narrow_no_throw()
21+
{
22+
long long bigNumber = 0x0fffffffffffffff;
23+
return gsl::narrow<int>(bigNumber);
24+
}
25+
26+
void test_terminate()
27+
{
28+
std::exit(0);
29+
}
30+
31+
void setup_termination_handler()
32+
{
33+
#if defined(_MSC_VER)
34+
35+
auto& handler = gsl::details::get_terminate_handler();
36+
handler = &test_terminate;
37+
38+
#else
39+
40+
std::set_terminate(test_terminate);
41+
42+
#endif
43+
}
44+
45+
46+
int main()
47+
{
48+
setup_termination_handler();
49+
narrow_no_throw();
50+
return -1;
51+
}

0 commit comments

Comments
 (0)