Skip to content

[Core] StatusOr<T> swap and assignment operate on unconstructed storage in the error state #64798

Description

@LuciferYang

What happened + What you expected to happen

ray::StatusOr<T> (src/ray/common/status_or.h) stores its value in a union member data_ that is only a live object when ok(); in the error state data_ is left unconstructed. Two paths do not respect that:

  1. swap() calls swap(data_, rhs.data_) unconditionally. When either operand is in the error state, this move-constructs from / assigns into unconstructed union storage — UB for any non-trivial T.

  2. operator=(const StatusOr&) and operator=(StatusOr&&) set status_ to OK before calling AssignValue. AssignValue destroys the existing value only when ok() is true, so with the status flipped first it runs data_.~T() on unconstructed storage whenever the destination was previously an error.

Every other path (copy/move ctor, AssignStatus) correctly guards on the pre-mutation ok() state; these two are the exceptions.

Expected: swapping or assigning into an error-state StatusOr<T> must not construct/destroy through the unconstructed union member.

swap is not called directly today but is reachable via ADL in generic code (std::swap, std::sort); the assignment operators are on common paths.

Versions / Dependencies

master (ray-project/ray), all platforms. C++ core (src/ray/common).

Reproduction script

No standalone script — found by code review. A unit test with a non-trivial T that assigns/swaps across error/value states (e.g. tracking live-instance count, or under ASan) exercises the UB; details in the linked PR.

Issue Severity

Medium: latent UB, narrow trigger (non-trivial T in an error state), but real.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions