ladybird/Userland/DevTools/UserspaceEmulator/ValueWithShadow.h
2022-12-03 23:52:23 +00:00

194 lines
4.9 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Format.h>
#include <AK/Platform.h>
#include <AK/UFixedBigInt.h>
#include <string.h>
namespace UserspaceEmulator {
template<typename T>
class ValueAndShadowReference;
template<typename T>
class ValueWithShadow {
public:
using ValueType = T;
using ShadowType = Array<u8, sizeof(T)>;
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<T> const&);
T value() const { return m_value; }
ShadowType const& shadow() const { return m_shadow; }
T shadow_as_value() const
requires(IsTriviallyConstructible<T>)
{
return *bit_cast<T const*>(m_shadow.data());
}
template<auto member>
auto reference_to()
requires(IsClass<T> || IsUnion<T>)
{
using ResultType = ValueAndShadowReference<RemoveReference<decltype(declval<T>().*member)>>;
return ResultType {
m_value.*member,
*bit_cast<typename ResultType::ShadowType*>(m_shadow.span().offset_pointer(bit_cast<u8*>(member) - bit_cast<u8*>(nullptr))),
};
}
template<auto member>
auto slice() const
requires(IsClass<T> || IsUnion<T>)
{
using ResultType = ValueWithShadow<RemoveReference<decltype(declval<T>().*member)>>;
return ResultType {
m_value.*member,
*bit_cast<typename ResultType::ShadowType*>(m_shadow.span().offset_pointer(bit_cast<u8*>(member) - bit_cast<u8*>(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<typename T>
class ValueAndShadowReference {
public:
using ValueType = T;
using ShadowType = Array<u8, sizeof(T)>;
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<T>& operator=(ValueWithShadow<T> const&);
T shadow_as_value() const
requires(IsTriviallyConstructible<T>)
{
return *bit_cast<T const*>(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<typename T>
ALWAYS_INLINE ValueWithShadow<T> shadow_wrap_as_initialized(T value)
{
return ValueWithShadow<T>::create_initialized(value);
}
template<typename T, typename U>
ALWAYS_INLINE ValueWithShadow<T> 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<typename T, typename U, typename V>
ALWAYS_INLINE ValueWithShadow<T> 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<typename T, typename U, typename V, typename X>
ALWAYS_INLINE ValueWithShadow<T> 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<typename T>
inline ValueWithShadow<T>::ValueWithShadow(ValueAndShadowReference<T> const& other)
: m_value(other.value())
, m_shadow(other.shadow())
{
}
template<typename T>
inline ValueAndShadowReference<T>& ValueAndShadowReference<T>::operator=(ValueWithShadow<T> const& other)
{
m_value = other.value();
m_shadow = other.shadow();
return *this;
}
}
template<typename T>
struct AK::Formatter<UserspaceEmulator::ValueWithShadow<T>> : AK::Formatter<T> {
ErrorOr<void> format(FormatBuilder& builder, UserspaceEmulator::ValueWithShadow<T> value)
{
return Formatter<T>::format(builder, value.value());
}
};