LibWasm: Fix UB in LibWasm

Now that `Optional<T&>` are trivially copyable/movable, it is
triggering Undefined Behaviour checks on GCC. We can resolve those
by using an union.
This commit is contained in:
Jonne Ransijn 2024-11-28 12:13:01 +01:00 committed by Ali Mohammad Pur
commit d7a721951e
Notes: github-actions[bot] 2024-12-04 00:59:38 +00:00

View file

@ -738,30 +738,31 @@ static_assert(sizeof(SockRecvResult) == 8);
template<typename TResult, typename Tag = u32> template<typename TResult, typename Tag = u32>
struct Result { struct Result {
Result(TResult&& result) Result(TResult&& result)
: bits {} : m_result(result)
, tag(0) , tag(0)
{ {
new (&bits) TResult(move(result));
} }
Result(Errno&& error) Result(Errno&& error)
: bits {} : m_error(error)
, tag(1) , tag(1)
{ {
new (&bits) Errno(error);
} }
Optional<TResult&> result() const static_assert(IsTriviallyDestructible<TResult>);
static_assert(IsTriviallyDestructible<Errno>);
Optional<TResult const&> result() const
{ {
if (tag == 0) if (tag == 0)
return *bit_cast<TResult*>(&bits[0]); return m_result;
return {}; return {};
} }
Optional<Errno&> error() const Optional<Errno const&> error() const
{ {
if (tag == 1) if (tag == 1)
return *bit_cast<Errno*>(&bits[0]); return m_error;
return {}; return {};
} }
@ -778,23 +779,25 @@ struct Result {
} }
private: private:
alignas(max(alignof(TResult), alignof(Errno))) u8 bits[max(sizeof(TResult), sizeof(Errno))]; union {
TResult m_result;
Errno m_error;
};
LittleEndian<Tag> tag; LittleEndian<Tag> tag;
}; };
template<typename Tag> template<typename Tag>
struct Result<void, Tag> { struct Result<void, Tag> {
Result() Result()
: error_bits {} : m_error()
, tag(0) , tag(0)
{ {
} }
Result(Errno&& error) Result(Errno&& error)
: error_bits {} : m_error(error)
, tag(1) , tag(1)
{ {
new (&error_bits) Errno(error);
} }
Optional<Empty> result() const Optional<Empty> result() const
@ -803,16 +806,16 @@ struct Result<void, Tag> {
return { Empty {} }; return { Empty {} };
return {}; return {};
} }
Optional<Errno&> error() const Optional<Errno const&> error() const
{ {
if (tag == 1) if (tag == 1)
return *bit_cast<Errno*>(&error_bits[0]); return m_error;
return {}; return {};
} }
bool is_error() const { return tag == 1; } bool is_error() const { return tag == 1; }
private: private:
alignas(Errno) u8 error_bits[sizeof(Errno)]; Errno m_error;
LittleEndian<Tag> tag; LittleEndian<Tag> tag;
}; };