Bug 1850713: remove duplicated setting of early hint preloader id in `ScriptLoader...
[gecko.git] / third_party / rlbox / include / rlbox_struct_support.hpp
blobbdd60275f0b7fdc54caeed4d58aaf4170db70b71
1 #pragma once
2 // IWYU pragma: private, include "rlbox.hpp"
3 // IWYU pragma: friend "rlbox_.*\.hpp"
5 #include <cstring>
6 #include <functional>
7 #include <type_traits>
9 #include "rlbox_conversion.hpp"
10 #include "rlbox_helpers.hpp"
11 #include "rlbox_types.hpp"
12 #include "rlbox_wrapper_traits.hpp"
14 namespace rlbox::detail {
16 template<typename T, typename T_Sbx, typename T_Enable = void>
17 struct convert_to_sandbox_equivalent_helper;
19 template<typename T, typename T_Sbx>
20 struct convert_to_sandbox_equivalent_helper<
22 T_Sbx,
23 std::enable_if_t<!std::is_class_v<T>>>
25 using type = typename rlbox_sandbox<
26 T_Sbx>::template convert_to_sandbox_equivalent_nonclass_t<T>;
29 template<typename T, typename T_Sbx>
30 using convert_to_sandbox_equivalent_t =
31 typename convert_to_sandbox_equivalent_helper<T, T_Sbx>::type;
33 // This is used by rlbox_load_structs_from_library to test the current namespace
34 struct markerStruct
35 {};
38 #define helper_create_converted_field(fieldType, fieldName, isFrozen) \
39 typename detail::convert_to_sandbox_equivalent_t<fieldType, T_Sbx> fieldName;
41 #define helper_no_op()
43 #define sandbox_equivalent_specialization(T, libId) \
44 template<typename T_Sbx> \
45 struct Sbx_##libId##_##T \
46 { \
47 sandbox_fields_reflection_##libId##_class_##T( \
48 helper_create_converted_field, \
49 helper_no_op) \
50 }; \
52 /* add convert_to_sandbox_equivalent_t specialization for new struct */ \
53 namespace detail { \
54 template<typename T_Template, typename T_Sbx> \
55 struct convert_to_sandbox_equivalent_helper< \
56 T_Template, \
57 T_Sbx, \
58 std::enable_if_t<std::is_same_v<T_Template, T>>> \
59 { \
60 using type = Sbx_##libId##_##T<T_Sbx>; \
61 }; \
64 #define helper_create_tainted_field( \
65 fieldType, fieldName, isFrozen, MaybeConst) \
66 MaybeConst tainted<fieldType, T_Sbx> fieldName;
68 #define helper_create_tainted_vol_field( \
69 fieldType, fieldName, isFrozen, MaybeConst) \
70 MaybeConst tainted_volatile<fieldType, T_Sbx> fieldName;
72 #define helper_convert_type(fieldType, fieldName, isFrozen) \
73 ::rlbox::detail::convert_type<T_Sbx, Direction, Context>( \
74 lhs.fieldName, rhs.fieldName, example_unsandboxed_ptr, sandbox_ptr);
76 #define helper_find_example_pointer_or_null(fieldType, fieldName, isFrozen) \
77 { \
78 const void* ret = fieldName.find_example_pointer_or_null(); \
79 if (ret != nullptr) { \
80 return ret; \
81 } \
84 #define tainted_data_specialization_helper(MaybeConst, T, libId) \
86 template<typename T_Sbx> \
87 class tainted_volatile<MaybeConst T, T_Sbx> \
88 { \
89 KEEP_CLASSES_FRIENDLY \
90 KEEP_CAST_FRIENDLY \
92 private: \
93 inline MaybeConst Sbx_##libId##_##T<T_Sbx>& \
94 get_sandbox_value_ref() noexcept \
95 { \
96 return *reinterpret_cast<MaybeConst Sbx_##libId##_##T<T_Sbx>*>(this); \
97 } \
99 inline const Sbx_##libId##_##T<T_Sbx>& get_sandbox_value_ref() \
100 const noexcept \
102 return *reinterpret_cast<const Sbx_##libId##_##T<T_Sbx>*>(this); \
105 inline T get_raw_value() const noexcept \
107 T lhs; \
108 const auto& rhs = get_sandbox_value_ref(); \
109 constexpr auto Direction = \
110 detail::adjust_type_direction::TO_APPLICATION; \
111 constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
112 /* This is a tainted_volatile, so its address is a valid example for use \
113 * as example_unsandboxed_ptr */ \
114 const void* example_unsandboxed_ptr = &rhs; \
115 rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
116 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
117 helper_no_op) \
119 return lhs; \
122 /* get_raw_sandbox_value has to return a custom struct to deal with the \
123 * adjusted machine model, to ensure */ \
124 inline Sbx_##libId##_##T<T_Sbx> get_raw_sandbox_value() const noexcept \
126 auto ret_ptr = reinterpret_cast<const Sbx_##libId##_##T<T_Sbx>*>(this); \
127 return *ret_ptr; \
130 tainted_volatile() = default; \
131 tainted_volatile(const tainted_volatile<MaybeConst T, T_Sbx>& p) = \
132 default; \
134 public: \
135 sandbox_fields_reflection_##libId##_class_##T( \
136 helper_create_tainted_vol_field, \
137 helper_no_op, \
138 MaybeConst) \
140 inline tainted<MaybeConst T*, T_Sbx> \
141 operator&() const noexcept \
143 auto ref_cast = \
144 reinterpret_cast<MaybeConst T*>(&get_sandbox_value_ref()); \
145 auto ret = tainted<MaybeConst T*, T_Sbx>::internal_factory(ref_cast); \
146 return ret; \
149 inline auto UNSAFE_unverified() const { return get_raw_value(); } \
150 inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
152 return get_raw_sandbox_value(sandbox); \
155 template<size_t N> \
156 inline auto unverified_safe_because(const char (&reason)[N]) const \
158 RLBOX_UNUSED(reason); \
159 return UNSAFE_unverified(); \
162 T copy_and_verify(std::function<T(tainted<T, T_Sbx>)> verifier) \
164 tainted<T, T_Sbx> val(*this); \
165 return verifier(val); \
168 /* Can't define this yet due, to mutually dependent definition between \
169 tainted and tainted_volatile for structs */ \
170 inline tainted_volatile<MaybeConst T, T_Sbx>& operator=( \
171 const tainted<T, T_Sbx>& rhs); \
172 }; \
174 template<typename T_Sbx> \
175 class tainted<MaybeConst T, T_Sbx> \
177 KEEP_CLASSES_FRIENDLY \
178 KEEP_CAST_FRIENDLY \
180 private: \
181 inline MaybeConst T& get_raw_value_ref() noexcept \
183 return *reinterpret_cast<MaybeConst T*>(this); \
186 inline const T& get_raw_value_ref() const noexcept \
188 return *reinterpret_cast<const T*>(this); \
191 inline T get_raw_value() const noexcept \
193 auto ret_ptr = reinterpret_cast<const T*>(this); \
194 return *ret_ptr; \
197 /* get_raw_sandbox_value has to return a custom struct to deal with the \
198 * adjusted machine model, to ensure */ \
199 inline Sbx_##libId##_##T<T_Sbx> get_raw_sandbox_value( \
200 rlbox_sandbox<T_Sbx>& sandbox) const noexcept \
202 Sbx_##libId##_##T<T_Sbx> lhs; \
203 const auto& rhs = get_raw_value_ref(); \
204 constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \
205 constexpr auto Context = detail::adjust_type_context::SANDBOX; \
206 const void* example_unsandboxed_ptr = nullptr; \
207 rlbox_sandbox<T_Sbx>* sandbox_ptr = &sandbox; \
208 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
209 helper_no_op) \
211 return lhs; \
214 inline const void* find_example_pointer_or_null() const noexcept \
216 sandbox_fields_reflection_##libId##_class_##T( \
217 helper_find_example_pointer_or_null, helper_no_op) \
219 return nullptr; \
222 public: \
223 sandbox_fields_reflection_##libId##_class_##T(helper_create_tainted_field, \
224 helper_no_op, \
225 MaybeConst) \
227 tainted() = default; \
228 tainted(const tainted<MaybeConst T, T_Sbx>& p) = default; \
230 tainted(const tainted_volatile<T, T_Sbx>& p) \
232 auto& lhs = get_raw_value_ref(); \
233 auto& rhs = p.get_sandbox_value_ref(); \
234 constexpr auto Direction = \
235 detail::adjust_type_direction::TO_APPLICATION; \
236 constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
237 /* This is a tainted_volatile, so its address is a valid for use as */ \
238 /* example_unsandboxed_ptr */ \
239 const void* example_unsandboxed_ptr = &rhs; \
240 rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
241 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
242 helper_no_op) \
245 inline tainted_opaque<MaybeConst T, T_Sbx> to_opaque() \
247 return *reinterpret_cast<tainted_opaque<MaybeConst T, T_Sbx>*>(this); \
250 inline auto UNSAFE_unverified() const { return get_raw_value(); } \
251 inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
253 return get_raw_sandbox_value(sandbox); \
256 template<size_t N> \
257 inline auto unverified_safe_because(const char (&reason)[N]) const \
259 RLBOX_UNUSED(reason); \
260 return UNSAFE_unverified(); \
263 T copy_and_verify(std::function<T(tainted<T, T_Sbx>)> verifier) \
265 return verifier(*this); \
267 }; \
269 /* Had to delay the definition due, to mutually dependence between \
270 tainted and tainted_volatile for structs */ \
271 template<typename T_Sbx> \
272 inline tainted_volatile<MaybeConst T, T_Sbx>& \
273 tainted_volatile<MaybeConst T, T_Sbx>::operator=( \
274 const tainted<T, T_Sbx>& rhs_wrap) \
276 auto& lhs = get_sandbox_value_ref(); \
277 auto& rhs = rhs_wrap.get_raw_value_ref(); \
278 constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \
279 constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
280 /* This is a tainted_volatile, so its address is a valid example for */ \
281 /* use as example_unsandboxed_ptr */ \
282 const void* example_unsandboxed_ptr = &lhs; \
283 rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
284 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
285 helper_no_op) \
287 return *this; \
290 #define tainted_data_specialization(T, libId) \
291 tainted_data_specialization_helper(, T, libId) \
292 tainted_data_specialization_helper(const, T, libId)
294 #define convert_type_specialization(T, libId) \
295 namespace detail { \
296 template<typename T_Sbx, \
297 detail::adjust_type_direction Direction, \
298 adjust_type_context Context, \
299 typename T_From> \
300 class convert_type_class<T_Sbx, Direction, Context, T, T_From> \
302 public: \
303 static inline void run(T& lhs, \
304 const T_From& rhs, \
305 const void* example_unsandboxed_ptr, \
306 rlbox_sandbox<T_Sbx>* sandbox_ptr) \
308 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
309 helper_no_op) \
311 }; \
313 template<typename T_Sbx, \
314 detail::adjust_type_direction Direction, \
315 adjust_type_context Context, \
316 typename T_From> \
317 class convert_type_class<T_Sbx, \
318 Direction, \
319 Context, \
320 Sbx_##libId##_##T<T_Sbx>, \
321 T_From> \
323 public: \
324 static inline void run(Sbx_##libId##_##T<T_Sbx>& lhs, \
325 const T_From& rhs, \
326 const void* example_unsandboxed_ptr, \
327 rlbox_sandbox<T_Sbx>* sandbox_ptr) \
329 sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
330 helper_no_op) \
332 }; \
335 // clang-format off
336 #define rlbox_load_structs_from_library(libId) \
337 namespace rlbox { \
338 /* check that this macro is called in a global namespace */ \
339 static_assert( \
340 ::rlbox::detail::is_member_of_rlbox_detail<detail::markerStruct>, \
341 "Invoke rlbox_load_structs_from_library in the global namespace"); \
343 sandbox_fields_reflection_##libId##_allClasses( \
344 sandbox_equivalent_specialization) \
346 sandbox_fields_reflection_##libId##_allClasses( \
347 tainted_data_specialization) \
349 sandbox_fields_reflection_##libId##_allClasses( \
350 convert_type_specialization) \
352 RLBOX_REQUIRE_SEMI_COLON
354 // clang-format on