#pragma once // IWYU pragma: private, include "rlbox.hpp" // IWYU pragma: friend "rlbox_.*\.hpp" #include #include #include #include #include #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 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 name(__VA_ARGS__) # define RLBOX_ACQUIRE_UNIQUE_GUARD(name, ...) \ std::unique_lock 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 \ 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>>; \ if constexpr (detail::rlbox_is_tainted_v && \ !std::is_reference_v) { \ return sandbox_const_cast>( \ const_cast(this)->func_name()); \ } else if constexpr (detail::is_fundamental_or_enum_v || \ detail::is_std_array_v || \ detail::is_func_ptr_v || \ std::is_class_v) { \ return const_cast(this)->func_name(); \ } else { \ return const_cast( \ const_cast(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>>; \ if constexpr (detail::rlbox_is_tainted_v && \ !std::is_reference_v) { \ static_assert(detail::rlbox_is_tainted_v); \ return sandbox_const_cast>( \ const_cast(this)->func_name(__VA_ARGS__)); \ } else if constexpr (detail::is_fundamental_or_enum_v || \ detail::is_std_array_v || \ detail::is_func_ptr_v || \ std::is_class_v) { \ return const_cast(this)->func_name(__VA_ARGS__); \ } else { \ return const_cast( \ const_cast(this)->func_name(__VA_ARGS__)); \ } #define rlbox_detail_member_and_const(sig, ...) \ sig __VA_ARGS__ \ \ sig const __VA_ARGS__ \ \ static_assert(true) template inline auto remove_volatile_from_ptr_cast(T* ptr) { using T_Result = std::add_pointer_t>; return const_cast(ptr); } // https://stackoverflow.com/questions/37602057/why-isnt-a-for-loop-a-compile-time-expression namespace compile_time_for_detail { template struct num { static const constexpr auto value = N; }; template inline void compile_time_for_helper(F func, std::index_sequence) { (func(num{}), ...); } } template inline void compile_time_for(F func) { compile_time_for_detail::compile_time_for_helper( func, std::make_index_sequence()); } template [[nodiscard]] inline auto return_first_result(T first_task, T2 second_task) { using T_Result = rlbox::detail::polyfill::invoke_result_t; if constexpr (std::is_void_v) { first_task(); second_task(); } else { auto val = first_task(); second_task(); return val; } } // Scope Exit guards template 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 [[nodiscard]] scope_exit make_scope_exit( T_ExitFunc&& exitFunction) { return scope_exit(std::move(exitFunction)); } /* Make sure classes can access the private memmbers of tainted and tainted_volatile. Ideally, this should be template friend class tainted; But C++ doesn't seem to allow the above */ #define KEEP_CLASSES_FRIENDLY \ template typename U1, typename U2, typename U3> \ friend class tainted_base_impl; \ \ template \ friend class tainted; \ \ template \ friend class tainted_volatile; \ \ template \ friend class rlbox_sandbox; \ \ template \ friend class sandbox_callback; } }