[Bug c++/93901] New: noexcept specifier on ctor does not work with constexpr variable or expression
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93901 Bug ID: 93901 Summary: noexcept specifier on ctor does not work with constexpr variable or expression Product: gcc Version: 10.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: paul.groke at dynatrace dot com Target Milestone: --- Seems like with GCC 10, only the literal `true` works as expected in noexcept specifiers for ctors. Other expressions that evaluate to "true" result in ctors that test as "noexcept(false)". Noexcept specifiers on functions seem to work just fine though. Example: #include #include extern void *mem; constexpr bool YES = true; struct NoexceptTrueCtor { NoexceptTrueCtor() noexcept(true); }; void NoexceptTrueFun() noexcept(true); struct NoexceptYesCtor { NoexceptYesCtor() noexcept(YES); }; void NoexceptYesFun() noexcept(YES); struct NoexceptOneEqOneCtor { NoexceptOneEqOneCtor() noexcept(1 == 1); }; void NoexceptOneEqOneFun() noexcept(1 == 1); struct NoNoexceptCtor { NoNoexceptCtor(); }; void NoNoexceptFun(); static_assert(std::is_nothrow_default_constructible::value, "1"); // OK static_assert(noexcept(new(mem) NoexceptTrueCtor), "2"); // OK static_assert(noexcept(NoexceptTrueFun()), "3"); // OK static_assert(std::is_nothrow_default_constructible::value, "4"); // fail static_assert(noexcept(new(mem) NoexceptYesCtor), "5"); // fail static_assert(noexcept(NoexceptYesFun()), "6"); // OK static_assert(std::is_nothrow_default_constructible::value, "7"); // fail static_assert(noexcept(new(mem) NoexceptOneEqOneCtor), "8"); // fail static_assert(noexcept(NoexceptOneEqOneFun()), "9"); // OK static_assert(!std::is_nothrow_default_constructible::value, "10"); // OK static_assert(!noexcept(new(mem) NoNoexceptCtor), "11"); // OK static_assert(!noexcept(NoNoexceptFun()), "12"); // OK This fails with :32:71: error: static assertion failed: 4 32 | static_assert(std::is_nothrow_default_constructible::value, "4"); // fail | ^ :33:15: error: static assertion failed: 5 33 | static_assert(noexcept(new(mem) NoexceptYesCtor), "5"); // fail | ^~ :36:76: error: static assertion failed: 7 36 | static_assert(std::is_nothrow_default_constructible::value, "7"); // fail | ~^ :37:15: error: static assertion failed: 8 37 | static_assert(noexcept(new(mem) NoexceptOneEqOneCtor), "8"); // fail | ^~~ Compiler returned: 1 Tested with godbolt.org: https://godbolt.org/z/BvXe4K x86-64, g++ (Compiler-Explorer-Build) 10.0.1 20200223 (experimental) GCC versions 9.2 and older compile the above code just fine as do Clang, MSVC and ICC.
[Bug c++/82270] New: incorrect warning [-Wignored-attributes]
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82270 Bug ID: 82270 Summary: incorrect warning [-Wignored-attributes] Product: gcc Version: 6.4.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: paul.groke at dynatrace dot com Target Milestone: --- Created attachment 42210 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=42210&action=edit Reproducer GCC version 6.4, SPARC 32 and 64 bit System: Solaris No command line options, i.e. just g++ test.cpp Compiler output is: test.cpp: In function 'int main()': test.cpp:19:21: warning: ignoring attributes on template argument 'type {aka type_fn<8u>}' [-Wignored-attributes] return meta_fn::value; ^ The following versions also emit the same incorrect warning: GCC version 6.3, ARM (but not ARM64) GCC version 6.2.1, MSP430 I haven't been able to reproduce the warning with any x86 compiler though - i.e. GCC 6.4 on Linux x86 doesn't emit the warning. If I understand this correctly, the warning is incorrect. The attribute is attached directly to the type (the struct), and thus must not be "lost" if using the type as a template argument. --- The following code also produces the same warning (tested with Boost 1.63, 1.64): #include int main() { boost::container::small_vector v; }
[Bug c++/82270] incorrect warning [-Wignored-attributes]
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82270 --- Comment #2 from Paul Groke --- I've contributed a workaround to Boost that avoids the bogus warning when using boost::container::small_vector: https://github.com/boostorg/move/pull/14 So if whoever fixes this wants to test with boost::container::small_vector, he/she should use Boost version <= 1.65.1.
[Bug libstdc++/98376] New: this_thread::sleep_for(short duration) can sleep forever on Linux
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98376 Bug ID: 98376 Summary: this_thread::sleep_for(short duration) can sleep forever on Linux Product: gcc Version: 11.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: paul.groke at dynatrace dot com Target Milestone: --- If libstdc++ is configured with _GLIBCXX_USE_NANOSLEEP (which seems to be the case on most systems), it will use nanosleep in this_thread::sleep_for like this: __gthread_time_t __ts = { static_cast(__s.count()), static_cast(__ns.count()) }; while (::nanosleep(&__ts, &__ts) == -1 && errno == EINTR) { } However on Linux, such a nanosleep loop can run forever because of a Linux bug that's documented here: https://man7.org/linux/man-pages/man2/nanosleep.2.html#BUGS For this to happen the thread needs to receive signals at a high frequency which seems to be rather uncommon. However there's a Go feature called non-cooperative preemption that can trigger this quite easily, see https://github.com/golang/proposal/blob/master/design/24543-non-cooperative-preemption.md https://github.com/golang/go/blob/master/src/runtime/signal_unix.go#L352 https://github.com/golang/go/blob/master/src/runtime/preempt.go#L223 This could lead to problems when on Linux, native code that uses libstdc++ is called from a Go thread. The Go thread executing this_thread::sleep_for will loop forever calling nanosleep and the other Go thread that tries to preempt it will also loop forever, perpetually trying to preempt it.
[Bug libstdc++/98376] this_thread::sleep_for(short duration) can sleep forever on Linux
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98376 --- Comment #1 from Paul Groke --- Sorry, I only realized that using links to master doesn't make much sense after I had already created the ticket. Those links should be stable: https://github.com/golang/proposal/blob/5b63da9579c3b19294be614dcad33e20a9a4ad22/design/24543-non-cooperative-preemption.md https://github.com/golang/go/blob/go1.15.6/src/runtime/signal_unix.go#L347 https://github.com/golang/go/blob/go1.15.6/src/runtime/preempt.go#L223
[Bug libstdc++/98376] this_thread::sleep_for(short duration) can sleep forever on Linux
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98376 --- Comment #2 from Paul Groke --- I was able to reproduce the problem with the following program (see below). It won't reproduce well on a loaded machine and you may have to fiddle with the spin counts to get a successful repro. I know this is a Linux bug, but since a lot of people are using Linux it might be worth implementing a workaround in libstdc++. Output from my machine: Remaining: 0.02000 - signal count: 0 Remaining: 0.312026100 - signal count: 6322 Remaining: 0.610834500 - signal count: 12729 Remaining: 0.907113100 - signal count: 19096 Remaining: 1.202000100 - signal count: 25452 Remaining: 1.499204500 - signal count: 31842 Remaining: 1.799767600 - signal count: 38277 Remaining: 2.095204700 - signal count: 44636 (...snip...) Remaining: 86.829101800 - signal count: 1865855 Remaining: 87.126722500 - signal count: 1872251 Remaining: 87.427912300 - signal count: 1878704 Remaining: 87.730148000 - signal count: 1885171 Remaining: 88.029529500 - signal count: 1891599 Remaining: 88.329424200 - signal count: 1898039 Remaining: 88.629499900 - signal count: 1904482 Remaining: 88.926003300 - signal count: 1910861 ERROR: timeout. sleep thread seems hung. --- #include #include #include #include #include #include #include using namespace std::chrono_literals; constexpr auto acq = std::memory_order_acquire; constexpr auto rlx = std::memory_order_relaxed; constexpr uint64_t sigHandlerSpin = 10'000; constexpr uint64_t sigSenderSpin = 100; constexpr int64_t sleepTimeNs = 20'000'000; // 20ms constexpr int64_t reportIntervalNs = 200'000'000; // 200ms constexpr auto timeout = 60s; thread_local bool tls_isSleepThread{false}; std::atomic s_signalCount{0}; std::atomic s_signalPending{false}; struct timespec makeTs(time_t sec, int64_t nsec) { struct timespec ts = {}; ts.tv_sec = sec; ts.tv_nsec = nsec; return ts; } void spinWait(uint64_t spinCount) { [[maybe_unused]] volatile int32_t dummy = 0; volatile int32_t divisor = 123456789; volatile int32_t dividend = 33; for (uint64_t i = 0; i < spinCount; i++) dummy = divisor / dividend; } void signalHandler(int) { if (tls_isSleepThread) { s_signalCount++; spinWait(sigHandlerSpin); } s_signalPending = false; }; void spinBarrier(std::atomic& barrier) { barrier--; while (barrier.load(acq)) { // wait... } } struct State { std::atomic startBarrier{3}; std::atomic stop{false}; std::atomic reportGen{0}; std::atomic reportSec{0}; std::atomic reportNsec{0}; }; [[maybe_unused]] void nanosleepThreadFn(State& state) { tls_isSleepThread = true; auto sleepTime = makeTs(0, sleepTimeNs); state.reportSec.store(sleepTime.tv_sec, rlx); state.reportNsec.store(sleepTime.tv_nsec, rlx); spinBarrier(state.startBarrier); while (!state.stop) { if (::nanosleep(&sleepTime, &sleepTime) != -1) break; if (errno != EINTR) break; auto gen = state.reportGen.load(acq); state.reportSec.store(sleepTime.tv_sec, rlx); state.reportNsec.store(sleepTime.tv_nsec, rlx); state.reportGen.store(gen + 1); } state.stop = true; } [[maybe_unused]] void stdSleepThreadFn(State& state) { tls_isSleepThread = true; auto sleepTime = 1ns * sleepTimeNs; spinBarrier(state.startBarrier); std::this_thread::sleep_for(sleepTime); state.stop = true; } void reportThreadFn(State& state) { auto const delay = makeTs(0, reportIntervalNs); spinBarrier(state.startBarrier); while (!state.stop) { // try to get consistent snapshot... int64_t sec; int64_t nsec; for (size_t i = 0; i < 10; i++) { auto const gen = state.reportGen.load(acq); spinWait(10); sec = state.reportSec.load(rlx); nsec = state.reportNsec.load(rlx); spinWait(10); auto const gen2 = state.reportGen.load(acq); if (gen2 == gen) break; } std::cout << "Remaining: " << sec << "." << std::setfill('0') << std::setw(9) << nsec << " - signal count: " << s_signalCount << std::endl; nanosleep(&delay, nullptr); } } int runTest() { s_signalCount = 0; s_signalPending = false; // install SIGURG handler... struct sigaction oldSigUrgAction = {}; struct sigaction sigUrgAction = {}; sigUrgAction.sa_handler = signalHandler; sigaction(SIGURG, &sigUrgAction, &oldSigUrgAction); auto* const state = new State{}; std::thread sleepThread{[state] { nanosleepThreadFn(*state); }}; std::thread reportThread{[state] { reportThreadFn(*state); }}; auto const sleepThreadHandle = sleepThread.native_handle(); spinBarrier(state->startBarrier); using Clock = std::chrono::steady_clock; auto const t0 = Clock::now(); // Ham
[Bug libstdc++/54185] [4.7/4.8 Regression] condition_variable not properly destructed
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54185 Paul Groke changed: What|Removed |Added CC||paul.groke at dynatrace dot com --- Comment #16 from Paul Groke --- (In reply to Jonathan Wakely) > It fails reliably on AIX too. I think that is because of non-conformant behavior of AIX's pthread_mutex_destroy. It will return EBUSY as long as there are still threads executing a wait function, even if they're already blocked on re-acquiring the mutex. If you ignore the error and simply releases/unmap the memory of the CV, you have a good chance of getting a SIGSEGV in the wait function later (after it has re-acquired the mutex and presumably proceeds to mark the CV "non-busy"). In our tests, we get the EBUSY every time if we delete the CV while holding the mutex on the same thread. The SIGSEGV also reproduces quite well, although for some reason only with 32 bit builds. (AIX 7.1, oslevel 7100-05-03-1837)
[Bug c++/82270] incorrect warning [-Wignored-attributes]
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82270 Paul Groke changed: What|Removed |Added Status|RESOLVED|REOPENED Resolution|DUPLICATE |--- --- Comment #4 from Paul Groke --- This is not the same as bug 97222. Bug 97222 is about losing attributes that were introduced by a typedef. This bug is about getting a bogus warning which says that this happened when: - The attribute is attached directly to a struct - The a typedef resolving to the struct is then used as a template argument - Compiling for SPARC - The attribute isn't really lost In what is described in bug 97222 OTOH, the attribute is really lost, because it was introduced by a typedef and not directly attached to a struct as in this case.
[Bug c++/109665] New: Incorrect code generation for s390/s390x try-catch (__cxa_begin_catch), causing SIGSEGV
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109665 Bug ID: 109665 Summary: Incorrect code generation for s390/s390x try-catch (__cxa_begin_catch), causing SIGSEGV Product: gcc Version: 12.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: paul.groke at dynatrace dot com Target Milestone: --- In certain situations, GCC generates incorrect s390x code for calling `__cxa_begin_catch`. The bogus code contains a `lghi %r2,0` right before calling `__cxa_begin_catch`. r2 is the register for the first and only argument of `__cxa_begin_catch`, which is a pointer to some struct related to the exception. And when called with a nullptr, `__cxa_begin_catch` will crash (SIGSEGV). s390 (`-m31`) is also affected. To reproduce, compile the following on Linux/s390x with at least `-O1`: ``` void f2(int, int, int, int, int); void f1() { try { f2(42, 42, 42, 42, 0); // SIGSEGV } catch (...) { } } ``` The resulting code with GCC 12.2.0 is this: ``` f1(): stmg %r6,%r15,48(%r15) lghi %r5,42 aghi %r15,-160 lghi %r6,0 lghi %r4,42 lghi %r3,42 lghi %r2,42 brasl %r14,_Z2f2i@PLT lg %r4,272(%r15) lmg %r6,%r15,208(%r15) br %r4 lghi %r2,0 brasl %r14,__cxa_begin_catch@PLT lmg %r6,%r15,208(%r15) jg __cxa_end_catch@PLT ``` See https://godbolt.org/z/TTYr63oM3 The correct code has an `lgr %r2,%r6` instead of the `lghi %r2,0`. The bug seems to be dependent on several factors: - The last thing in the try-catch is a function call with at least 5 parameters (Note that I only tested with parameter types that each fit into a general purpose register though) - The 5th argument must be a zero constant (0, false, ...) - The try-catch contains a "catch (...)" handler - At least `-O1` is used - The function call is not inlined/no constant propagation happens I found the bug with GCC 9.5.0 but it also happens with at least 11.2.0, 12.1.0 and 12.2.0 (tested with godbolt.org). I don't have newer GCC versions for s390x handy, so I didn't test with those.
[Bug target/109665] Incorrect code generation for s390/s390x try-catch (__cxa_begin_catch), causing SIGSEGV
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109665 --- Comment #2 from Paul Groke --- -fno-schedule-insns and/or -fno-schedule-insns2 don't change the instruction sequence for calling __cxa_begin_catch. BTW: for compiler versions present there, it's super easy to check this with godbolt.org. Just enter the compiler switches into the text-field next to the compiler selection control.
[Bug target/109665] Incorrect code generation for s390/s390x try-catch (__cxa_begin_catch), causing SIGSEGV
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109665 --- Comment #3 from Paul Groke --- Created attachment 54952 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=54952&action=edit Minimal repro Added minimal repro