Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Format.h>
10#include <AK/Platform.h>
11#include <AK/UFixedBigInt.h>
12#include <string.h>
13
14namespace UserspaceEmulator {
15
16template<typename T>
17class ValueAndShadowReference;
18
19template<typename T>
20class ValueWithShadow {
21public:
22 using ValueType = T;
23 using ShadowType = Array<u8, sizeof(T)>;
24
25 ValueWithShadow() = default;
26
27 ValueWithShadow(T value, T shadow)
28 : m_value(value)
29 {
30 ReadonlyBytes { &shadow, sizeof(shadow) }.copy_to(m_shadow);
31 }
32
33 ValueWithShadow(T value, ShadowType shadow)
34 : m_value(value)
35 , m_shadow(shadow)
36 {
37 }
38
39 static ValueWithShadow create_initialized(T value)
40 {
41 ShadowType shadow;
42 shadow.fill(0x01);
43 return {
44 value,
45 shadow,
46 };
47 }
48
49 ValueWithShadow(ValueAndShadowReference<T> const&);
50
51 T value() const { return m_value; }
52 ShadowType const& shadow() const { return m_shadow; }
53
54 T shadow_as_value() const
55 requires(IsTriviallyConstructible<T>)
56 {
57 return *bit_cast<T const*>(m_shadow.data());
58 }
59
60 template<auto member>
61 auto reference_to()
62 requires(IsClass<T> || IsUnion<T>)
63 {
64 using ResultType = ValueAndShadowReference<RemoveReference<decltype(declval<T>().*member)>>;
65 return ResultType {
66 m_value.*member,
67 *bit_cast<typename ResultType::ShadowType*>(m_shadow.span().offset_pointer(bit_cast<u8*>(member) - bit_cast<u8*>(nullptr))),
68 };
69 }
70
71 template<auto member>
72 auto slice() const
73 requires(IsClass<T> || IsUnion<T>)
74 {
75 using ResultType = ValueWithShadow<RemoveReference<decltype(declval<T>().*member)>>;
76 return ResultType {
77 m_value.*member,
78 *bit_cast<typename ResultType::ShadowType*>(m_shadow.span().offset_pointer(bit_cast<u8*>(member) - bit_cast<u8*>(nullptr))),
79 };
80 }
81
82 bool is_uninitialized() const
83 {
84 for (size_t i = 0; i < sizeof(ShadowType); ++i) {
85 if ((m_shadow[i] & 0x01) != 0x01)
86 return true;
87 }
88 return false;
89 }
90
91 void set_initialized()
92 {
93 m_shadow.fill(0x01);
94 }
95
96private:
97 T m_value {};
98 ShadowType m_shadow {};
99};
100
101template<typename T>
102class ValueAndShadowReference {
103public:
104 using ValueType = T;
105 using ShadowType = Array<u8, sizeof(T)>;
106
107 ValueAndShadowReference(T& value, ShadowType& shadow)
108 : m_value(value)
109 , m_shadow(shadow)
110 {
111 }
112
113 bool is_uninitialized() const
114 {
115 for (size_t i = 0; i < sizeof(ShadowType); ++i) {
116 if ((m_shadow[i] & 0x01) != 0x01)
117 return true;
118 }
119 return false;
120 }
121
122 ValueAndShadowReference<T>& operator=(ValueWithShadow<T> const&);
123
124 T shadow_as_value() const
125 requires(IsTriviallyConstructible<T>)
126 {
127 return *bit_cast<T const*>(m_shadow.data());
128 }
129
130 T& value() { return m_value; }
131 ShadowType& shadow() { return m_shadow; }
132
133 T const& value() const { return m_value; }
134 ShadowType const& shadow() const { return m_shadow; }
135
136private:
137 T& m_value;
138 ShadowType& m_shadow;
139};
140
141template<typename T>
142ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_as_initialized(T value)
143{
144 return ValueWithShadow<T>::create_initialized(value);
145}
146
147template<typename T, typename U>
148ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_with_taint_from(T value, U const& taint_a)
149{
150 if (taint_a.is_uninitialized())
151 return { value, 0 };
152 return shadow_wrap_as_initialized(value);
153}
154
155template<typename T, typename U, typename V>
156ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_with_taint_from(T value, U const& taint_a, V const& taint_b)
157{
158 if (taint_a.is_uninitialized() || taint_b.is_uninitialized())
159 return { value, 0 };
160 return shadow_wrap_as_initialized(value);
161}
162
163template<typename T, typename U, typename V, typename X>
164ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_with_taint_from(T value, U const& taint_a, V const& taint_b, X const& taint_c)
165{
166 if (taint_a.is_uninitialized() || taint_b.is_uninitialized() || taint_c.is_uninitialized())
167 return { value, 0 };
168 return shadow_wrap_as_initialized(value);
169}
170
171template<typename T>
172inline ValueWithShadow<T>::ValueWithShadow(ValueAndShadowReference<T> const& other)
173 : m_value(other.value())
174 , m_shadow(other.shadow())
175{
176}
177
178template<typename T>
179inline ValueAndShadowReference<T>& ValueAndShadowReference<T>::operator=(ValueWithShadow<T> const& other)
180{
181 m_value = other.value();
182 m_shadow = other.shadow();
183 return *this;
184}
185
186}
187
188template<typename T>
189struct AK::Formatter<UserspaceEmulator::ValueWithShadow<T>> : AK::Formatter<T> {
190 ErrorOr<void> format(FormatBuilder& builder, UserspaceEmulator::ValueWithShadow<T> value)
191 {
192 return Formatter<T>::format(builder, value.value());
193 }
194};