Re: Non-reproducible AIO failure
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: Konstantin Knizhnik <knizhnik@garret.ru>
Cc: pgsql-hackers@lists.postgresql.org
Date: 2025-06-06T19:21:13Z
Lists: pgsql-hackers
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
aio: Stop using enum bitfields due to bad code generation
- ce161b194e84 18.0 landed
- 5865150b6d53 19 (unreleased) landed
-
amcheck: Fix posting tree checks in gin_index_check()
- 0cf205e122ae 18.0 cited
-
aio: Add missing memory barrier when waiting for IO handle
- e9a3615a5224 18.0 landed
Konstantin Knizhnik <knizhnik@garret.ru> writes:
> There is really essential difference in code generated by clang 15
> (working) and 16 (not working).
It's a mistake to think that this is a compiler bug. The C standard
explicitly allows compilers to use word-wide operations to access
bit-field struct members. Such accesses may fetch or overwrite other
bit-fields in the same word, using a non-atomic read/modify/write
sequence. I don't have a recent C standard at hand, but I found this
quote on the web [1]:
The C Standard, 3.17, paragraph 3 [ISO/IEC 9899:2024], states
Note 2 to entry: A bit-field and an adjacent non-bit-field member
are in separate memory locations. The same applies to two
bit-fields, if one is declared inside a nested structure
declaration and the other is not, or if the two are separated by a
zero-length bit-field declaration, or if they are separated by a
non-bit-field member declaration. It is not safe to concurrently
update two non-atomic bit-fields in the same structure if all
members declared between them are also (nonzero-length)
bit-fields, no matter what the sizes of those intervening
bit-fields happen to be.
So it's our code that is busted. No doubt, what is happening is
that process A is fetching two fields, modifying one of them,
and storing the word back (with the observed value of the other
field) concurrently with some other process trying to update
the other field. So the other process's update is lost.
If we want to preserve the compactness of this struct, we have
to use primitive int types not bit-fields.
regards, tom lane
[1] https://wiki.sei.cmu.edu/confluence/display/c/CON32-C.+Prevent+data+races+when+accessing+bit-fields+from+multiple+threads