2
#include <iostream>
#include <thread>
#include <chrono>
#include <functional>

template <typename F, typename... Ts>
inline void FuncDetach(F &&f, Ts &&...args)
{
    std::thread th{[&f, &args...]() {
        do
        {
            auto func = std::bind(std::forward<F>(f), std::forward<Ts>(args)...);
            func(args...);
        } while (true);
    }};
    th.detach();
}

auto func()
{
    std::cout << "normal func" << std::endl;
}

class CL
{
public:
    auto func() {std::cout << "member func" << std::endl;}
};

int main()
{
    FuncDetach(func); // gcc and clang no problem

    CL c;
    FuncDetach(&CL::func, &c); // segmentation fault in gcc, but not in clang
    std::this_thread::sleep_for(std::chrono::minutes(2));
    return 0;
}

There is only "normal func" output in gcc, and then "Segmentation fault" appears. "normal func" and "member func" in clang will always output.

I don't think this has anything to do with the life cycle of c, because it is obvious that c has not been destroyed. At the same time, I also noticed that -lpthread is not required for compiling with clang. So, can someone tell me what the problem is? Thank you very much!

Xiaoying Sun
  • 21
  • 1
  • 3
  • 1
    I see `//pause` is commented out, what stops the program exiting either before or during the execution of the thread? – Richard Critten Apr 27 '21 at 16:46
  • 1
    Your thread may have started running that endless loop when the program is terminating, ripping its guts out. – Ted Lyngmo Apr 27 '21 at 16:47
  • @RichardCritten //pause means calling sleep here to make the program pause – Xiaoying Sun Apr 27 '21 at 16:52
  • @XiaoyingSun post the real code please - how can we help you if the posted code is not the code you are having the problem with. Please read [ask] with a [mcve]. – Richard Critten Apr 27 '21 at 16:53
  • Is the segment fault immediate or only after the timer has expired ? – Richard Critten Apr 27 '21 at 16:56
  • @RichardCritten immediately – Xiaoying Sun Apr 27 '21 at 16:56
  • What happens to `c` when it goes out of scope? What happens when your thread tries to call the member function in `c` when `c` doesn't exist anymore? Questions like that are interesting. – Ted Lyngmo Apr 27 '21 at 17:00
  • 1
    You should also probably do `auto func = std::bind(std::forward(f), std::forward(args)...);` before the loop and just call `func()` inside the loop. I don't know what `func(args...);` would result in ... – Ted Lyngmo Apr 27 '21 at 17:06
  • 1
    Please post a [mcve], these code fragments are fun to look at but we need something that builds. – n. m. could be an AI Apr 27 '21 at 17:46
  • After adding `#include ` to compile, I can reproduce the problem. `AddressSanitizer: stack-use-after-scope` well. – KamilCuk Apr 27 '21 at 18:05
  • 1
    There is much strangeness going on when capturing by reference. Copying [seems to work](https://godbolt.org/z/fGxGhKoqE). My guess is that the arguments passed to `FuncDetach` are removed from the stack when the function returns and all the references become dangling....somehow. Can't put my finger on it yet. – Ted Lyngmo Apr 27 '21 at 18:21
  • 1
    @TedLyngmo: The arguments given *to* `f` are ignored, since no placeholders were used in its construction. – Davis Herring Apr 27 '21 at 18:58
  • @DavisHerring Ah... that's what's going on. I'm crap at `std::bind`. So [this](https://godbolt.org/z/G61cTf8Y8) is "pretty ok" wrt the arguments then I guess. I know I let `c` be destroyed while the thread is running, which in itself makes it UB since it's calling a member func in `c`, but at least the arguments should be ok... – Ted Lyngmo Apr 27 '21 at 19:21

1 Answers1

1

While c is "never destroyed", the parameters to FuncDetach are references to the temporaries materialized for the prvalue arguments (the pointer-to-member and pointer, respectively), and their by-reference captures become invalid when the call returns (they might live until the end of the full-expression, but that's the same point here). Undefined behavior is undefined.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76