• Andres Freund's avatar
    Fix fallback implementation of pg_atomic_write_u32(). · b0779abb
    Andres Freund authored
    I somehow had assumed that in the spinlock (in turn possibly using
    semaphores) based fallback atomics implementation 32 bit writes could be
    done without a lock. As far as the write goes that's correct, since
    postgres supports only platforms with single-copy atomicity for aligned
    32bit writes.  But writing without holding the spinlock breaks
    read-modify-write operations like pg_atomic_compare_exchange_u32(),
    since they'll potentially "miss" a concurrent write, which can't happen
    in actual hardware implementations.
    
    In 9.6+ when using the fallback atomics implementation this could lead
    to buffer header locks not being properly marked as released, and
    potentially some related state corruption.  I don't see a related danger
    in 9.5 (earliest release with the API), because pg_atomic_write_u32()
    wasn't used in a concurrent manner there.
    
    The state variable of local buffers, before this change, were
    manipulated using pg_atomic_write_u32(), to avoid unnecessary
    synchronization overhead. As that'd not be the case anymore, introduce
    and use pg_atomic_unlocked_write_u32(), which does not correctly
    interact with RMW operations.
    
    This bug only caused issues when postgres is compiled on platforms
    without atomics support (i.e. no common new platform), or when compiled
    with --disable-atomics, which explains why this wasn't noticed in
    testing.
    
    Reported-By: Tom Lane
    Discussion: <14947.1475690465@sss.pgh.pa.us>
    Backpatch: 9.5-, where the atomic operations API was introduced.
    b0779abb
generic.h 9.96 KB