mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-12 22:22:55 +00:00
194 lines
4.9 KiB
C++
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());
|
|
}
|
|
};
|