Skip to content

__cxa_guard_acquire()'s guard byte check doesn't conform to CPPABI64 #145386

Open
@asl

Description

@asl

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++abilibc++abi C++ Runtime Library. Not libc++.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions