mercredi 27 février 2019

Segfault when stripping .gnu.version section

I'm in the process of rewriting legacy code based on an old Framework with C++11 using thread and chrono libraries. To summarize the library spawns a thread and waits either an event or a delay.

I've written a code sample that works well until I strip the .gnu.version section.

1. Compilation

g++ -std=c++11 test.cpp -o test -pthread -lpthread

2. Execution before strip

$ ./test
>>run()
  run() - before wait()
>>wait()
< wait()
  run() - after wait()
  run() - before wait_until()
  run() - after wait_until()
  run() - before wait()
  run() - after wait()
< run()

3. Strip .gnu.version section

strip -R .gnu.version test

4. Execution after strip

 ./test
>>run()
  run() - before wait()
>>wait()
< wait()
  run() - after wait()
  run() - before wait_until()
Segmentation fault (core dumped)

From what I was able to investigate the segfault occurs in std::condition_variable::.wait_until() when calling the undelaying pthread library.

Here is the code sample :

#include <thread>
#include <iostream>
#include <condition_variable>
#include <unistd.h>

class Task
{
private:
    std::mutex _mutex;
    std::condition_variable _cv;
    std::thread _thread;
    bool _bStop;
    bool _bWait;

    void run()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        std::cout << ">>run()" << std::endl;
        while (!_bStop)
        {
            if ( !_bWait )
            {
                std::cout << "  run() - before wait()" << std::endl;
                _cv.wait(lock);
                std::cout << "  run() - after wait()" << std::endl;
            }
            else
            {
                _bWait = false;
                std::chrono::steady_clock::time_point ts = std::chrono::steady_clock::now()
                                                         + std::chrono::seconds(1);
                std::cout << "  run() - before wait_until()" << std::endl;
                _cv.wait_until(lock,ts);
                std::cout << "  run() - after wait_until()" << std::endl;
            }
        }
        std::cout << "< run()" << std::endl;
    }

public:
    Task():_bStop(false),_bWait(false)
    {
    }

    void start()
    {
        _thread = std::thread(&Task::run,this);
    }

    void wait()
    {
        std::cout << ">>wait()" << std::endl;
        std::unique_lock<std::mutex> lock(_mutex);
        _bWait = true;
        _cv.notify_one();
        std::cout << "< wait()" << std::endl;
    }

    void cancel()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _bStop = true;
        _cv.notify_one();
    }

    void join()
    {
        _thread.join();
    }
};

int main()
{
    Task t;

    // Start Task thread
    t.start();

    // Sleeping here seems to help produce the error
    usleep(10000);
    t.wait();

    // Wait for Task to process delay
    sleep(5);

    // Stop Task and wait for thread termination
    t.cancel();
    t.join();

    return 0;
}

Aucun commentaire:

Enregistrer un commentaire