AK: Apply empty base optimization to Variant on Windows

On the MSVC ABI (used by clang-cl), each empty base class is given a
unique address with 1 byte of padding by default. Variant inherits from
a deep chain of empty base classes (InheritFromPacks ->
InheritFromUniqueEntries -> VariantConstructors) for its inherited
constructor mechanism. Without __declspec(empty_bases), the pointer
adjustment in VariantConstructors::internal_cast() from the
VariantConstructors subobject back to the Variant base was computed
incorrectly due to accumulated padding, causing the constructor to write
m_data and m_index at wrong offsets and corrupting the stored object.

This manifested as heap corruption (STATUS_HEAP_CORRUPTION 0xc0000374)
whenever a Variant containing a large type (e.g. ByteCode at 240 bytes)
was destroyed after being constructed through the inherited constructor
path. In practice this crashed `new RegExp('a')` in LibJS on Windows,
preventing ~880 of ~1058 LibJS runtime tests from running.
This commit is contained in:
kalenikaliaksandr
2026-03-24 22:05:30 +01:00
committed by Alexander Kalenik
parent 1d025620e3
commit 70a1a9e82f
Notes: github-actions[bot] 2026-03-24 23:59:03 +00:00

View File

@@ -191,7 +191,7 @@ struct InheritFromUniqueEntries;
// as that has already been checked before.
// This makes sure that the search is linear in time (like the 'merge' step of merge sort).
template<size_t I, typename... Ts, size_t... Js, typename... Qs>
struct InheritFromUniqueEntries<I, ParameterPack<Ts...>, IndexSequence<Js...>, Qs...>
struct AK_COMPACT_EMPTY_BASES InheritFromUniqueEntries<I, ParameterPack<Ts...>, IndexSequence<Js...>, Qs...>
: public BlankIfDuplicate<Ts, Conditional<Js <= I, ParameterPack<>, Qs>...>... {
using BlankIfDuplicate<Ts, Conditional<Js <= I, ParameterPack<>, Qs>...>::BlankIfDuplicate...;
@@ -203,7 +203,7 @@ struct InheritFromPacks;
// InheritFromPacks will attempt to 'merge' the pack 'Ps' with *itself*, but skip the duplicate entries
// (via InheritFromUniqueEntries).
template<size_t... Is, typename... Ps>
struct InheritFromPacks<IndexSequence<Is...>, Ps...>
struct AK_COMPACT_EMPTY_BASES InheritFromPacks<IndexSequence<Is...>, Ps...>
: public InheritFromUniqueEntries<Is, Ps, IndexSequence<Is...>, Ps...>... {
using InheritFromUniqueEntries<Is, Ps, IndexSequence<Is...>, Ps...>::InheritFromUniqueEntries...;
@@ -225,7 +225,7 @@ template<typename T>
concept NotLvalueReference = !IsLvalueReference<T>;
template<NotLvalueReference... Ts>
struct Variant
struct AK_COMPACT_EMPTY_BASES Variant
: public Detail::MergeAndDeduplicatePacks<Detail::VariantConstructors<Ts, Variant<Ts...>>...> {
public:
using IndexType = Conditional<(sizeof...(Ts) < 255), u8, size_t>; // Note: size+1 reserved for internal value checks