https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65033
Bug ID: 65033 Summary: C++11 atomics: is_lock_free result does not always match the real lock-free property Product: gcc Version: 4.9.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: bin.x.fan at oracle dot com Hi, The is_lock_free result for an object of type atomic<s3_t>, where s3_t is size=3, alignment=1 C style struct, does not always match the implementation in libatomic.so for atomic operations on this object. I think there is either a bug in the g++ header <atomic> and the g++ 4.9.2 implementation is not C++11 standard conforming, or there is a bug in libatomic.so. Here is the source code -bash-4.1$ cat struct3.cc #include <atomic> #include <stdio.h> using namespace std; #define N 10 struct s3_t { char a[3]; }; atomic<s3_t> array[N]; s3_t obj; int main() { int i; for (i=0;i<N;i++) { printf ("%x\t", &array[i]); printf("%d\t", __atomic_always_lock_free(sizeof(array[i]), &array[i])); printf("%d\t", atomic_is_lock_free (&array[i])); printf("size: %d, align: %d\n", sizeof(array[i]), alignof(array[i])); } for (i=0;i<N;i++) { atomic_store (&array[i], obj); } return 0; } The bug is found on Solaris-SPARC, but it could be on other platforms as well. The Solaris OS version is 11.2 Here is my g++ version. -bash-4.1$ g++ -v Using built-in specs. COLLECT_GCC=/net/dv104/export/tools/gcc/4.9.2/sparc-S2/bin/g++.bin COLLECT_LTO_WRAPPER=/net/dv104/export/tools/gcc/4.9.2/sparc-S2/libexec/gcc/sparc-sun-solaris2.10/4.9.2/lto-wrapper Target: sparc-sun-solaris2.10 Configured with: ../gcc-4.9.2/configure --prefix=/net/dv104/export/tools/gcc/4.9.2/sparc-S2 --enable-languages=c,c++,fortran --with-gmp=/net/dv104/export/tools/gcc/4.9.2/sparc-S2 --with-mpfr=/net/dv104/export/tools/gcc/4.9.2/sparc-S2 --with-mpc=/net/dv104/export/tools/gcc/4.9.2/sparc-S2 Thread model: posix gcc version 4.9.2 (GCC) Here is the compiling options and run result: -bash-4.1$ g++ -latomic -std=c++11 struct3.cc -bash-4.1$ ./a.out 21680 0 1 size: 3, align: 1 21683 0 1 size: 3, align: 1 21686 0 1 size: 3, align: 1 21689 0 1 size: 3, align: 1 2168c 0 1 size: 3, align: 1 2168f 0 1 size: 3, align: 1 21692 0 1 size: 3, align: 1 21695 0 1 size: 3, align: 1 21698 0 1 size: 3, align: 1 2169b 0 1 size: 3, align: 1 The result seems correct. The atomic_is_lock_free always returns 1, which conform to the C++11 standard 29.4: "The function atomic_is_lock_free (29.6) indicates whether the object is lock-free. In any given program execution, the result of the lock-free query shall be consistent for all pointers of the same type." So the lock-free property is per-type, not per-object. atomic_is_lock_free always returning 1 is a conforming behavior. However, on SPARC, it's impossible to guarantee a 1-byte aligned 3-byte object to be always lock-free. That was my first clue of this bug. Digging it further, I found that for some objects, the atomic_store operation is locked. To verify it, I ran the program under debugger and set a breakpoint at function libat_lock_n, and I saw it is called. =>[1] libat_lock_n(ptr = 0x216c6, n = 3U), line 64 in "lock.c" [2] libat_store(n = 3U, mptr = 0x216c6, vptr = 0xffbff580, smodel = 5), line 100 in "gstore.c" [3] std::atomic<s3_t>::store(this = 0x216c6, __i = STRUCT, _m = memory_order_seq_cst), line 199 in "atomic" [4] std::atomic_store_explicit<s3_t>(__a = 0x216c6, __i = STRUCT, __m = memory_order_seq_cst), line 828 in "atomic" [5] std::atomic_store<s3_t>(__a = 0x216c6, __i = STRUCT), line 895 in "atomic" [6] main(), line 22 in "struct3.cc" So one of the following two things could be happening here 1. g++ makes lock-free property per-object, which is not C++11 standard conforming, and report it incorrectly with atomic_is_lock_free, or 2. g++ tries to make lock-free property per-type, but the libatomic.so implementation does not match. Also, without changing the alignment, I doubt that size=3 alignment=1 atomic object can always be lock-free on SPARC or x86.