/* * Copyright (c) 2020, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace UserspaceEmulator { template class ValueAndShadowReference; template class ValueWithShadow { public: using ValueType = T; using ShadowType = Array; ValueWithShadow() = default; ValueWithShadow(T value, T shadow) : m_value(value) { ReadonlyBytes { &shadow, sizeof(shadow) }.copy_to(m_shadow); } ValueWithShadow(T value, ShadowType shadow) : m_value(value) , m_shadow(shadow) { } static ValueWithShadow create_initialized(T value) { ShadowType shadow; shadow.fill(0x01); return { value, shadow, }; } ValueWithShadow(ValueAndShadowReference const&); T value() const { return m_value; } ShadowType const& shadow() const { return m_shadow; } T shadow_as_value() const requires(IsTriviallyConstructible) { return *bit_cast(m_shadow.data()); } template auto reference_to() requires(IsClass || IsUnion) { using ResultType = ValueAndShadowReference().*member)>>; return ResultType { m_value.*member, *bit_cast(m_shadow.span().offset_pointer(bit_cast(member) - bit_cast(nullptr))), }; } template auto slice() const requires(IsClass || IsUnion) { using ResultType = ValueWithShadow().*member)>>; return ResultType { m_value.*member, *bit_cast(m_shadow.span().offset_pointer(bit_cast(member) - bit_cast(nullptr))), }; } bool is_uninitialized() const { for (size_t i = 0; i < sizeof(ShadowType); ++i) { if ((m_shadow[i] & 0x01) != 0x01) return true; } return false; } void set_initialized() { m_shadow.fill(0x01); } private: T m_value {}; ShadowType m_shadow {}; }; template class ValueAndShadowReference { public: using ValueType = T; using ShadowType = Array; ValueAndShadowReference(T& value, ShadowType& shadow) : m_value(value) , m_shadow(shadow) { } bool is_uninitialized() const { for (size_t i = 0; i < sizeof(ShadowType); ++i) { if ((m_shadow[i] & 0x01) != 0x01) return true; } return false; } ValueAndShadowReference& operator=(ValueWithShadow const&); T shadow_as_value() const requires(IsTriviallyConstructible) { return *bit_cast(m_shadow.data()); } T& value() { return m_value; } ShadowType& shadow() { return m_shadow; } T const& value() const { return m_value; } ShadowType const& shadow() const { return m_shadow; } private: T& m_value; ShadowType& m_shadow; }; template ALWAYS_INLINE ValueWithShadow shadow_wrap_as_initialized(T value) { return ValueWithShadow::create_initialized(value); } template ALWAYS_INLINE ValueWithShadow shadow_wrap_with_taint_from(T value, U const& taint_a) { if (taint_a.is_uninitialized()) return { value, 0 }; return shadow_wrap_as_initialized(value); } template ALWAYS_INLINE ValueWithShadow shadow_wrap_with_taint_from(T value, U const& taint_a, V const& taint_b) { if (taint_a.is_uninitialized() || taint_b.is_uninitialized()) return { value, 0 }; return shadow_wrap_as_initialized(value); } template ALWAYS_INLINE ValueWithShadow shadow_wrap_with_taint_from(T value, U const& taint_a, V const& taint_b, X const& taint_c) { if (taint_a.is_uninitialized() || taint_b.is_uninitialized() || taint_c.is_uninitialized()) return { value, 0 }; return shadow_wrap_as_initialized(value); } template inline ValueWithShadow::ValueWithShadow(ValueAndShadowReference const& other) : m_value(other.value()) , m_shadow(other.shadow()) { } template inline ValueAndShadowReference& ValueAndShadowReference::operator=(ValueWithShadow const& other) { m_value = other.value(); m_shadow = other.shadow(); return *this; } } template struct AK::Formatter> : AK::Formatter { ErrorOr format(FormatBuilder& builder, UserspaceEmulator::ValueWithShadow value) { return Formatter::format(builder, value.value()); } };