Can a default/zero-initialized empty struct be filled with "arbitrary" bits?

Hello C++ language lawyers,

Let’s say we have this code that has UB:

union Flag {
    constexpr Flag() : empty{} {}

    struct {} empty;
    bool value;
};

static Flag flag;

int main() {
    return flag.value;
}

where the UB is accessing value when it’s not the active member of the union Flag.

Currently, UBSan will not catch this error because (as I understand it) UBSan does not have a check for it. Implementing one might be hard and involve introducing some global state to UBSan or an ABI change. However, for this particular case, we think UBSan could catch some UB going on here indirectly via the same check for non-true/false values for type bool. If the byte of an empty struct is considered “uninitialized” or “can have any arbitrary value”, and if we had something akin to -fauto-var-init=pattern that set these arbitrary bytes to 0xAA, then UBSan would be able to catch the load of the 0xAA as an invalid value for bool. We’ve caught a lot of bugs via the -fauto-var-init=pattern + UBSan bool check for traditional auto stack variables, and we think we could catch more bugs of this nature if we extend this to globals.

The main question is: Is it semantically permissible to have the nominal byte of empty structs–and more generally, any padding bytes in all structs–be initialized to 0xaa or such nonzero pattern?

Leonard

Zero initialization does initialize padding, so empty being an non-potentially-overlapping object, it “owns” 1 byte (that is zeroed).

Somewhat related is CWG Issue 2536.