Date: Thu, 26 May 2022 11:18:26 +0200

On 26/05/2022 10.02, language.lawyer--- via Std-Discussion wrote:

>> std::pair<int16_t, int16_t> mixed_size() {

>> int32_t x = 0;

>>

>> {

>> auto x_atomic = std::atomic_ref<int32_t>(x);

>> x_atomic.store(0xabbafafa, std::memory_order_relaxed);

>> // atomic_ref lifetime ends so we can use x again

>> }

>>

>> auto x_parts = reinterpret_cast<int16_t*>(&x);

>> int16_t& x_left = x_parts[0];

>> int16_t& x_right = x_parts[1];

>

> The last two lines have undefined behavior.

... irrespective of anything "atomic"; there is

no "array of int16_t" object at x, so you're

violating the pointer arithmetic and/or aliasing

rules.

The following example:

> std::int32_t mixed_atomicity() {

> int32_t x = 0;

>

> {

> auto x_atomic = std::atomic_ref<int32_t>(x);

> x_atomic.store(42, std::memory_order_relaxed);

> // atomic_ref lifetime ends so we can use x again

> }

>

> // Obviously reading 42 is sane here, but there is no codified semantics

> // governing non-atomically reading an atomic location in any circumstance

> int32_t read = x;

> returnread;

> }

just uses the plain non-atomic semantics; the atomic store stored a value

into x (in addition to all the concurrency effects the atomic store might

have), and the usual lvalue-to-rvalue conversion then reads the value of x.

Jens

>> std::pair<int16_t, int16_t> mixed_size() {

>> int32_t x = 0;

>>

>> {

>> auto x_atomic = std::atomic_ref<int32_t>(x);

>> x_atomic.store(0xabbafafa, std::memory_order_relaxed);

>> // atomic_ref lifetime ends so we can use x again

>> }

>>

>> auto x_parts = reinterpret_cast<int16_t*>(&x);

>> int16_t& x_left = x_parts[0];

>> int16_t& x_right = x_parts[1];

>

> The last two lines have undefined behavior.

... irrespective of anything "atomic"; there is

no "array of int16_t" object at x, so you're

violating the pointer arithmetic and/or aliasing

rules.

The following example:

> std::int32_t mixed_atomicity() {

> int32_t x = 0;

>

> {

> auto x_atomic = std::atomic_ref<int32_t>(x);

> x_atomic.store(42, std::memory_order_relaxed);

> // atomic_ref lifetime ends so we can use x again

> }

>

> // Obviously reading 42 is sane here, but there is no codified semantics

> // governing non-atomically reading an atomic location in any circumstance

> int32_t read = x;

> returnread;

> }

just uses the plain non-atomic semantics; the atomic store stored a value

into x (in addition to all the concurrency effects the atomic store might

have), and the usual lvalue-to-rvalue conversion then reads the value of x.

Jens

Received on 2022-05-26 09:18:29