Description
The generic C++ ABI GCPPABI specifies the bottom byte of a static variable guard variable shall be 0 when the variable is not initialized, and 1 when it is. All other bytes are platform defined.
ARM CPPABI64 further refines down to:
This ABI instead only specifies the value bit 0 of the static guard variable; all other bits are platform defined. Bit 0 shall be 0 when the variable is not initialized and 1 when it is.
However, libcxxabi checks whether the whole init byte is != 0 regardless of the platform:
/// The guard byte portion of cxa_guard_acquire. Returns true if
/// initialization has already been completed.
bool acquire() {
// if guard_byte is non-zero, we have already completed initialization
// (i.e. release has been called)
return guard_byte.load(std::_AO_Acquire) != UNSET;
}
https://github.com/llvm/llvm-project/blob/main/libcxxabi/src/cxa_guard_impl.h#L196
This means that if the guard byte has a value != 0 with the lowest bit == 0 (i.e., 2), the guard byte is still treated as initialized, even though it is not according to CPPABI64.
This doesn't look like it will cause any problems, since the initial value of the whole guard variable is 0, and the guard byte is set to 1 (which has the lowest bit set) in __cxa_guard_release()
.
So, the question is if this is something that should be fixed (to == COMPLETE_BIT
), or left as-is, or if there are any security / correctness implications here.