diff options
Diffstat (limited to 'third_party/rlbox/include/rlbox_noop_sandbox.hpp')
-rw-r--r-- | third_party/rlbox/include/rlbox_noop_sandbox.hpp | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/third_party/rlbox/include/rlbox_noop_sandbox.hpp b/third_party/rlbox/include/rlbox_noop_sandbox.hpp new file mode 100644 index 0000000000..d1e48edb4f --- /dev/null +++ b/third_party/rlbox/include/rlbox_noop_sandbox.hpp @@ -0,0 +1,254 @@ +#pragma once + +#include <cstdint> +#include <cstdlib> +#include <mutex> +#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK +# include <shared_mutex> +#endif +#include <utility> + +#include "rlbox_helpers.hpp" + +namespace rlbox { + +class rlbox_noop_sandbox; + +struct rlbox_noop_sandbox_thread_data +{ + rlbox_noop_sandbox* sandbox; + uint32_t last_callback_invoked; +}; + +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + +rlbox_noop_sandbox_thread_data* get_rlbox_noop_sandbox_thread_data(); +# define RLBOX_NOOP_SANDBOX_STATIC_VARIABLES() \ + thread_local rlbox::rlbox_noop_sandbox_thread_data \ + rlbox_noop_sandbox_thread_info{ 0, 0 }; \ + namespace rlbox { \ + rlbox_noop_sandbox_thread_data* get_rlbox_noop_sandbox_thread_data() \ + { \ + return &rlbox_noop_sandbox_thread_info; \ + } \ + } \ + static_assert(true, "Enforce semi-colon") + +#endif + +/** + * @brief Class that implements the null sandbox. This sandbox doesn't actually + * provide any isolation and only serves as a stepping stone towards migrating + * an application to use the RLBox API. + */ +class rlbox_noop_sandbox +{ +public: + // Stick with the system defaults + using T_LongLongType = long long; + using T_LongType = long; + using T_IntType = int; + using T_PointerType = void*; + using T_ShortType = short; + // no-op sandbox can transfer buffers as there is no sandboxings + // Thus transfer is a noop + using can_grant_deny_access = void; + +private: + RLBOX_SHARED_LOCK(callback_mutex); + static inline const uint32_t MAX_CALLBACKS = 64; + void* callback_unique_keys[MAX_CALLBACKS]{ 0 }; + void* callbacks[MAX_CALLBACKS]{ 0 }; + +#ifndef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + thread_local static inline rlbox_noop_sandbox_thread_data thread_data{ 0, 0 }; +#endif + + template<uint32_t N, typename T_Ret, typename... T_Args> + static T_Ret callback_trampoline(T_Args... params) + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_noop_sandbox_thread_data(); +#endif + thread_data.last_callback_invoked = N; + using T_Func = T_Ret (*)(T_Args...); + T_Func func; + { +#ifndef RLBOX_SINGLE_THREADED_INVOCATIONS + RLBOX_ACQUIRE_SHARED_GUARD(lock, thread_data.sandbox->callback_mutex); +#endif + func = reinterpret_cast<T_Func>(thread_data.sandbox->callbacks[N]); + } + // Callbacks are invoked through function pointers, cannot use std::forward + // as we don't have caller context for T_Args, which means they are all + // effectively passed by value + return func(params...); + } + +protected: + inline void impl_create_sandbox() {} + + inline void impl_destroy_sandbox() {} + + template<typename T> + inline void* impl_get_unsandboxed_pointer(T_PointerType p) const + { + return p; + } + + template<typename T> + inline T_PointerType impl_get_sandboxed_pointer(const void* p) const + { + return const_cast<T_PointerType>(p); + } + + template<typename T> + static inline void* impl_get_unsandboxed_pointer_no_ctx( + T_PointerType p, + const void* /* example_unsandboxed_ptr */, + rlbox_noop_sandbox* (* // Func ptr + /* param: expensive_sandbox_finder */)( + const void* example_unsandboxed_ptr)) + { + return p; + } + + template<typename T> + static inline T_PointerType impl_get_sandboxed_pointer_no_ctx( + const void* p, + const void* /* example_unsandboxed_ptr */, + rlbox_noop_sandbox* (* // Func ptr + /* param: expensive_sandbox_finder */)( + const void* example_unsandboxed_ptr)) + { + return const_cast<T_PointerType>(p); + } + + inline T_PointerType impl_malloc_in_sandbox(size_t size) + { + void* p = malloc(size); + return p; + } + + inline void impl_free_in_sandbox(T_PointerType p) { free(p); } + + static inline bool impl_is_in_same_sandbox(const void*, const void*) + { + return true; + } + + inline bool impl_is_pointer_in_sandbox_memory(const void*) { return true; } + inline bool impl_is_pointer_in_app_memory(const void*) { return true; } + + inline size_t impl_get_total_memory() + { + return std::numeric_limits<size_t>::max(); + } + + inline void* impl_get_memory_location() + { + // There isn't any sandbox memory for the noop_sandbox as we just redirect + // to the app. Also, this is mostly used for pointer swizzling or sandbox + // bounds checks which is also not present/not required. So we can just + // return null + return nullptr; + } + + // adding a template so that we can use static_assert to fire only if this + // function is invoked + template<typename T = void> + void* impl_lookup_symbol(const char* /* func_name */) + { + // Will fire if this impl_lookup_symbol is ever called for the static + // sandbox + constexpr bool fail = std::is_same_v<T, void>; + rlbox_detail_static_fail_because( + fail, + "The no_op_sandbox uses static calls and thus developers should add\n\n" + "#define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol\n\n" + "to their code, to ensure that static calls are handled correctly."); + + return nullptr; + } + +#define rlbox_noop_sandbox_lookup_symbol(func_name) \ + reinterpret_cast<void*>(&func_name) /* NOLINT */ + + template<typename T, typename T_Converted, typename... T_Args> + auto impl_invoke_with_func_ptr(T_Converted* func_ptr, T_Args&&... params) + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_noop_sandbox_thread_data(); +#endif + auto old_sandbox = thread_data.sandbox; + thread_data.sandbox = this; + auto on_exit = detail::make_scope_exit([&] { + thread_data.sandbox = old_sandbox; + }); + return (*func_ptr)(params...); + } + + template<typename T_Ret, typename... T_Args> + inline T_PointerType impl_register_callback(void* key, void* callback) + { + RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex); + + void* chosen_trampoline = nullptr; + + // need a compile time for loop as we we need I to be a compile time value + // this is because we are returning the I'th callback trampoline + detail::compile_time_for<MAX_CALLBACKS>([&](auto I) { + if (!chosen_trampoline && callback_unique_keys[I.value] == nullptr) { + callback_unique_keys[I.value] = key; + callbacks[I.value] = callback; + chosen_trampoline = reinterpret_cast<void*>( + callback_trampoline<I.value, T_Ret, T_Args...>); + } + }); + + return reinterpret_cast<T_PointerType>(chosen_trampoline); + } + + static inline std::pair<rlbox_noop_sandbox*, void*> + impl_get_executed_callback_sandbox_and_key() + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_noop_sandbox_thread_data(); +#endif + auto sandbox = thread_data.sandbox; + auto callback_num = thread_data.last_callback_invoked; + void* key = sandbox->callback_unique_keys[callback_num]; + return std::make_pair(sandbox, key); + } + + template<typename T_Ret, typename... T_Args> + inline void impl_unregister_callback(void* key) + { + RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex); + for (uint32_t i = 0; i < MAX_CALLBACKS; i++) { + if (callback_unique_keys[i] == key) { + callback_unique_keys[i] = nullptr; + callbacks[i] = nullptr; + break; + } + } + } + + template<typename T> + inline T* impl_grant_access(T* src, size_t num, bool& success) + { + RLBOX_UNUSED(num); + success = true; + return src; + } + + template<typename T> + inline T* impl_deny_access(T* src, size_t num, bool& success) + { + RLBOX_UNUSED(num); + success = true; + return src; + } +}; + +} |