1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
|
#pragma once
// IWYU pragma: private, include "rlbox.hpp"
// IWYU pragma: friend "rlbox_.*\.hpp"
#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <type_traits>
#include <utility>
#include "rlbox_stdlib_polyfill.hpp"
namespace rlbox {
namespace detail {
const int CompileErrorCode = 42;
inline void dynamic_check(bool check, const char* const msg)
{
// clang-format off
if (!check) {
#if __cpp_exceptions && defined(RLBOX_USE_EXCEPTIONS)
throw std::runtime_error(msg);
#else
std::cerr << msg << std::endl;
std::abort();
#endif
}
// clang-format on
}
#ifdef RLBOX_NO_COMPILE_CHECKS
# if __cpp_exceptions && defined(RLBOX_USE_EXCEPTIONS)
# define rlbox_detail_static_fail_because(CondExpr, Message) \
((void)(CondExpr)), throw std::runtime_error(Message)
# else
# define rlbox_detail_static_fail_because(CondExpr, Message) abort()
# endif
#else
# define rlbox_detail_static_fail_because(CondExpr, Message) \
static_assert(!(CondExpr), Message)
#endif
#ifdef RLBOX_ENABLE_DEBUG_ASSERTIONS
# define RLBOX_DEBUG_ASSERT(...) \
::rlbox::detail::dynamic_check(__VA_ARGS__, "Debug assertion failed")
#else
# define RLBOX_DEBUG_ASSERT(...) (void)0
#endif
#define RLBOX_UNUSED(...) (void)__VA_ARGS__
#define RLBOX_REQUIRE_SEMI_COLON static_assert(true)
#define if_constexpr_named(varName, ...) \
if constexpr (constexpr auto varName = __VA_ARGS__; varName)
template<typename... TArgs>
void printTypes()
{
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
std::cout << __PRETTY_FUNCTION__ << std::endl; // NOLINT
#elif defined(_MSC_VER)
std::cout << __FUNCSIG__ << std::endl; // NOLINT
#else
std::cout << "Unsupported" << std::endl;
#endif
}
// Create an extension point so applications can provide their own shared lock
// implementation
#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
# define RLBOX_SHARED_LOCK(name) std::shared_timed_mutex name
# define RLBOX_ACQUIRE_SHARED_GUARD(name, ...) \
std::shared_lock<std::shared_timed_mutex> name(__VA_ARGS__)
# define RLBOX_ACQUIRE_UNIQUE_GUARD(name, ...) \
std::unique_lock<std::shared_timed_mutex> name(__VA_ARGS__)
#else
# if !defined(RLBOX_SHARED_LOCK) || !defined(RLBOX_ACQUIRE_SHARED_GUARD) || \
!defined(RLBOX_ACQUIRE_UNIQUE_GUARD)
# error \
"RLBOX_USE_CUSTOM_SHARED_LOCK defined but missing definitions for RLBOX_SHARED_LOCK, RLBOX_ACQUIRE_SHARED_GUARD, RLBOX_ACQUIRE_UNIQUE_GUARD"
# endif
#endif
#define rlbox_detail_forward_binop_to_base(opSymbol, ...) \
template<typename T_Rhs> \
inline auto operator opSymbol(T_Rhs rhs) \
{ \
auto b = static_cast<__VA_ARGS__*>(this); \
return (*b)opSymbol rhs; \
} \
RLBOX_REQUIRE_SEMI_COLON
#define rlbox_detail_forward_to_const(func_name, result_type) \
using T_ConstClassPtr = std::add_pointer_t< \
std::add_const_t<std::remove_pointer_t<decltype(this)>>>; \
if constexpr (detail::rlbox_is_tainted_v<result_type> && \
!std::is_reference_v<result_type>) { \
return sandbox_const_cast<detail::rlbox_remove_wrapper_t<result_type>>( \
const_cast<T_ConstClassPtr>(this)->func_name()); \
} else if constexpr (detail::is_fundamental_or_enum_v<result_type> || \
detail::is_std_array_v<result_type> || \
detail::is_func_ptr_v<result_type> || \
std::is_class_v<result_type>) { \
return const_cast<T_ConstClassPtr>(this)->func_name(); \
} else { \
return const_cast<result_type>( \
const_cast<T_ConstClassPtr>(this)->func_name()); \
}
#define rlbox_detail_forward_to_const_a(func_name, result_type, ...) \
using T_ConstClassPtr = std::add_pointer_t< \
std::add_const_t<std::remove_pointer_t<decltype(this)>>>; \
if constexpr (detail::rlbox_is_tainted_v<result_type> && \
!std::is_reference_v<result_type>) { \
static_assert(detail::rlbox_is_tainted_v<result_type>); \
return sandbox_const_cast<detail::rlbox_remove_wrapper_t<result_type>>( \
const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__)); \
} else if constexpr (detail::is_fundamental_or_enum_v<result_type> || \
detail::is_std_array_v<result_type> || \
detail::is_func_ptr_v<result_type> || \
std::is_class_v<result_type>) { \
return const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__); \
} else { \
return const_cast<result_type>( \
const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__)); \
}
#define rlbox_detail_member_and_const(sig, ...) \
sig __VA_ARGS__ \
\
sig const __VA_ARGS__ \
\
static_assert(true)
template<typename T>
inline auto remove_volatile_from_ptr_cast(T* ptr)
{
using T_Result = std::add_pointer_t<std::remove_volatile_t<T>>;
return const_cast<T_Result>(ptr);
}
// https://stackoverflow.com/questions/37602057/why-isnt-a-for-loop-a-compile-time-expression
namespace compile_time_for_detail {
template<std::size_t N>
struct num
{
static const constexpr auto value = N;
};
template<class F, std::size_t... Is>
inline void compile_time_for_helper(F func, std::index_sequence<Is...>)
{
(func(num<Is>{}), ...);
}
}
template<std::size_t N, typename F>
inline void compile_time_for(F func)
{
compile_time_for_detail::compile_time_for_helper(
func, std::make_index_sequence<N>());
}
template<typename T, typename T2>
[[nodiscard]] inline auto return_first_result(T first_task, T2 second_task)
{
using T_Result = rlbox::detail::polyfill::invoke_result_t<T>;
if constexpr (std::is_void_v<T_Result>) {
first_task();
second_task();
} else {
auto val = first_task();
second_task();
return val;
}
}
// Scope Exit guards
template<typename T_ExitFunc>
class scope_exit
{
T_ExitFunc exit_func;
bool released;
public:
explicit scope_exit(T_ExitFunc&& cleanup)
: exit_func(cleanup)
, released(true)
{}
scope_exit(scope_exit&& rhs)
: exit_func(std::move(rhs.exit_func))
, released(rhs.released)
{
rhs.release();
}
~scope_exit()
{
if (released) {
exit_func();
}
}
void release() { released = false; }
private:
explicit scope_exit(const scope_exit&) = delete;
scope_exit& operator=(const scope_exit&) = delete;
scope_exit& operator=(scope_exit&&) = delete;
};
template<typename T_ExitFunc>
[[nodiscard]] scope_exit<T_ExitFunc> make_scope_exit(
T_ExitFunc&& exitFunction)
{
return scope_exit<T_ExitFunc>(std::move(exitFunction));
}
/*
Make sure classes can access the private memmbers of tainted<T1> and
tainted_volatile. Ideally, this should be
template <typename U1>
friend class tainted<U1, T_Sandbox>;
But C++ doesn't seem to allow the above
*/
#define KEEP_CLASSES_FRIENDLY \
template<template<typename, typename> typename U1, typename U2, typename U3> \
friend class tainted_base_impl; \
\
template<typename U1, typename U2> \
friend class tainted; \
\
template<typename U1, typename U2> \
friend class tainted_volatile; \
\
template<typename U1> \
friend class rlbox_sandbox; \
\
template<typename U1, typename U2> \
friend class sandbox_callback;
}
}
|