std::call_once() hangs on second call after callable threw on first call
Asked Answered
W

1

11

Given this piece of code:

#include <mutex>
#include <iostream>

void f(bool doThrow) {
    if (doThrow) {
        std::cout << "Throwing" << std::endl;
        throw 42;
    }
    std::cout << "Not throwing" << std::endl;
}

std::once_flag flag;

void g(bool doThrow) {
    try {
        std::call_once(flag, f, doThrow);
        std::cout << "Returning" << std::endl;
    } catch (int i) {
        std::cout << "Caught " << i << std::endl;
    }
}

int main() {
    std::once_flag flag;
    g(true);
    g(true);
    g(false);
    g(true);
    g(false);
}

When compiled with g++ -std=c++11 -pthread -ggdb I get the output:

Throwing
Caught 42

after which the process hangs:

#0  0x000003fff7277abf in futex_wait (private=0, expected=1, futex_word=0x2aaaacad144 <flag>) at ../sysdeps/unix/sysv/linux/futex-internal.h:61
#1  futex_wait_simple (private=0, expected=1, futex_word=0x2aaaacad144 <flag>) at ../sysdeps/nptl/futex-internal.h:135
#2  __pthread_once_slow (once_control=0x2aaaacad144 <flag>, init_routine=0x3fff7a8d870 <std::__once_proxy()>) at pthread_once.c:105
#3  0x000002aaaaaab06f in __gthread_once (__once=0x2aaaacad144 <flag>, __func=0x3fff7a8d870 <std::__once_proxy()>) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/x86_64-pc-linux-gnu/bits/gthr-default.h:699
#4  0x000002aaaaaab6c8 in std::call_once<void (&)(bool), bool&> (__once=..., __f=@0x2aaaaaab08c: {void (bool)} 0x2aaaaaab08c <f(bool)>) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/mutex:738
#5  0x000002aaaaaab192 in g (doThrow=true) at test.cpp:17
#6  0x000002aaaaaab287 in main () at test.cpp:27

But when compiled with clang++ -std=c++11 -pthread -ggdb I get:

Throwing
Caught 42
Throwing
Caught 42
Not throwing
Returning
Returning
Returning

As far as I know this seems to be the correct behavior.

Is this a GCC bug, just me being confused over the semantics of std::call_once, or is my code incorrect?

Woodbridge answered 18/1, 2017 at 10:57 Comment(10)
Replicated, seems like a bug.Chartres
@Meninx-メネンックス so what? One is a part of the other.Amphitrite
@user2079303 Check this linkDisunite
gcc 6.3.1 doesn't hang, but bails out: terminate called after throwing an instance of 'std::system_error' what(): Unknown error -1 Pseudohermaphroditism
@Meninx-メネンックス so, you referred to the compiler driver by "gcc"? How is that relevant to this question then? It is not mentioned once.Amphitrite
@Meninx-メネンックス This is about GCC (as in the GNU Compiler Collection), not gcc.Woodbridge
@SamVarshavchik I think you are missing -pthread when compiling. See GCC PR 55394.Woodbridge
Yeah, that was it.Pseudohermaphroditism
I did not know that every compiler driver has a tag in SO. Thanks for clarifying.Disunite
@Meninx-メネンックス actually, all compiler drivers do not have a tag. gcc in particuar does not have, because gcc tag is used for the gnu compiler collection.Amphitrite
C
9

This looks to be a bug in the GNU C++ Library.


Surely this is a bug since even the default std::call_once example from cppreference will hang if you try to use the provided online compiler (Coliru) :)

The bug happens in g++ linux implementation which uses pthreads. What puzzled me is that this Wandbox example runs just fine. I checked the versions of libstdc++:

  • Wandbox: GLIBCXX: 20130411
  • Coliru: GLIBCXX: 20161221

Therefore I believe it is a libstdc++ bug, probably this one, or more precisely this one.

Coherence answered 18/1, 2017 at 14:30 Comment(1)
This has nothing to do with libstdc++, the std::call_once code is identical on x86 and ppc, and you get the same behaviour with pthreads, so it should be reported to glibc instead, from this.Cockroach

© 2022 - 2024 — McMap. All rights reserved.