Serenity Operating System
at master 194 lines 5.0 kB view raw
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};