分段错误malloc_consolidate

时间:2017-02-03 13:39:06

标签: c++ opencv

我正在运行此代码(为了保持点而简化):

int main(int argc, char** argv) {

    char* videoPath = args[1];

    DataSource* dataSource;
    std::thread dataSourceThread;
    dataSource = new FileDataSource(0.5f, true);
    dataSourceThread = std::thread(&FileDataSource::start, (FileDataSource*)dataSource, videoPath, 50);


    logger->info("FileDataSource started");
    float invScale = 1.f / dataSource->getScale();

    cv::Mat frame;
    unsigned long bufferIndexPrev = 0;
    unsigned long t;

    cv::Mat projMat(3, 4, CV_32F);
    cv::Mat rVec, tVec;

    while (!dataSource->isRunning()) std::this_thread::yield();
    logger->info("Data source running");

    Tracker tracker;
    tracker.dataSource = dataSource;
    std::thread trackerThread(&Tracker::start, &tracker);

    while (tracker.stateBuffer == nullptr) std::this_thread::yield();
    logger->info("Tracker started");

    while (true) {
        int bufferIndex = tracker.stateBuffer->bufferIndex;
        if (bufferIndex == bufferIndexPrev) {
            if (dataSource->isRunning()) {
                // std::this_thread::sleep_for(std::chrono::milliseconds(1));
                std::this_thread::yield();
                continue;
            }
            else {
                break;
            }
        }
        bufferIndexPrev = bufferIndex;


        State& state = tracker.stateBuffer->buffer[bufferIndex];
        Data data = state.data;

        int lastProcessedFrameNum = tracker.stateBuffer->buffer[bufferIndex].dataPacket.frameNumber;

        dataSource->getOriginalFrameByFrameNum(lastProcessedFrameNum, frame);

        cv::putText(frame, "Processing", cv::Point(20, 30), CV_FONT_HERSHEY_PLAIN, 2, CV_RGB(255, 0, 0)); 
     // ^^^^^^^^^ this line causes the crash
        cv::putText(frame, std::to_string(lastProcessedFrameNum), cv::Point(200, 30), CV_FONT_HERSHEY_PLAIN, 2, CV_RGB(255, 255, 0));

        std::vector<cv::KeyPoint> keypoints = state.keypoints;
        std::vector<int> indices = state.indices;
        for (int i = 0; i < keypoints.size(); i++) {
            cv::Point2f detectedPoint = keypoints[i].pt * invScale;
            if (state.indices[i] >= 0)
                cv::drawMarker(frame, detectedPoint, CV_RGB(0, 255, 0), cv::MARKER_CROSS);
            else 
                cv::drawMarker(frame, detectedPoint, CV_RGB(255, 0, 0), cv::MARKER_CROSS);


        }


        cv::imshow("Video", frame);

        int key = cv::waitKey(10);
        if (key == 32) {
            tracker.nextPhase();
        }

    }

    logger->info("Exited main loop");

    if (trackerThread.joinable()) trackerThread.join();
    if (dataSourceThread.joinable()) dataSourceThread.join();

    return 0;
}

现在,程序有时分段错误(SIGSEGV)上崩溃

cv::putText(frame, "Processing", cv::Point(20, 30), CV_FONT_HERSHEY_PLAIN, 2, CV_RGB(255, 0, 0));

我使用GDB调试它。我看到它的方式,唯一可能导致问题的是矩阵对象frame。 我也可以确认这一点,因为如果我放置cv::Mat的另一个实例而不是frame,代码永远不会崩溃。

数据源正在运行自己的获取视频帧并将其放入循环缓冲区的循环。主程序在需要时从该缓冲区中获取视频帧。

void FileDataSource::start(char* fileVideoPath, int fps) {

    logger->info("FileDataSource opening FileVideo {}", fileVideoPath);
    FileVideo video(fileVideoPath);

    unsigned long period = 1.e+6 / fps; // microseconds
    std::chrono::microseconds periodDuration(period);

    std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
    while (true) {
        int nextBufferIndex = (bufferIndex + 1) % bufferSize;
        cv::Mat& originalFrame = originalFrameBuffer[nextBufferIndex];
        bool success = video.getFrame(originalFrame);
        if (!success) break;

        cv::Mat& reducedFrame = reducedFrameBuffer[nextBufferIndex];
        cvtColor(originalFrame, reducedFrame, CV_BGR2GRAY);
        if (!this->presized) resize(reducedFrame, reducedFrame, cv::Size(), scale, scale);

        frameNumBuffer[nextBufferIndex] = frameNumBuffer[bufferIndex] + 1;
        tBuffer[nextBufferIndex] = tBuffer[bufferIndex] + period;
        bufferIndex = nextBufferIndex;
        this->running = true;
        std::this_thread::sleep_until(now + periodDuration);
        now = std::chrono::system_clock::now();
    }

    this->running = false;
}

void FileDataSource::getOriginalFrameByFrameNum(unsigned long frameNum, cv::Mat& frame) {

    int lBufferIndex = this->bufferIndex;
    for (int i = 0; i < bufferSize; i++)
    {
        if (frameNumBuffer[lBufferIndex] == frameNum) break;
        lBufferIndex = (lBufferIndex - 1 + bufferSize) % bufferSize;
    }

    frame = originalFrameBuffer[lBufferIndex];
}

tracker既不会读取也不会写入originalFrameBuffer,只会从reducedFrameBuffer读取,但这不会显示在代码中,因为帖子足够大。

another SO question我了解分段错误的本质:

  

分段错误是一种由访问引起的特定错误   记忆“不属于你。”它是一种帮助机制   使您免于破坏内存并引入难以调试   内存错误。每当你遇到段错误时,你就知道自己在做什么   内存有问题 - 访问已经存在的变量   释放,写入内存的只读部分等。

我真的不明白这是如何适用于我的情况的。有什么想法吗?

GDB回溯显示:

Thread 1 "videoGTKExample" received signal SIGSEGV, Segmentation fault.
0x00007fffed095281 in malloc_consolidate () from /lib/libc.so.6
(gdb) bt
#0  0x00007fffed095281 in malloc_consolidate () at /lib/libc.so.6
#1  0x00007fffed096d2a in _int_malloc () at /lib/libc.so.6
#2  0x00007fffed098d44 in malloc () at /lib/libc.so.6
#3  0x00007fffed966a78 in operator new(unsigned long) (sz=8192) at /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/new_op.cc:50
#4  0x00007fffeed3d684 in cv::putText(cv::_InputOutputArray const&, cv::String const&, cv::Point_<int>, int, double, cv::Scalar_<double>, int, int, bool) ()
    at /usr/local/lib/libopencv_imgproc.so.3.1
#5  0x00000000004a920b in main(int, char**) (argc=4, argv=0x7fffffffe0d8) at /home/andro/tracker/examples/videoGTKExample.cpp:180

P.S。 如果我用valgrind运行代码,我无法重现错误,因为它执行得慢得多,并且线程的并发性似乎不再是问题。

更新

我通过以下方式设法重现了SIGSEGV崩溃:

valgrind --tool=exp-sgcheck

生成的日志为here。我不确定这是否是同样的错误,因为它发生在没有定期发生的行。我是valgrind的新手,不知道这个日志中是否有任何有用的东西。我所看到的只是一个堆栈跟踪,类似于我在正常的gdb会话中看到的。

更新2:

gdb我有时(很少)会遇到以下崩溃:

Thread 1 "videoGTKExample" received signal SIGABRT, Aborted.
0x00007fffed05104f in raise () from /lib/libc.so.6
(gdb) bt
#0  0x00007fffed05104f in raise () at /lib/libc.so.6
#1  0x00007fffed05247a in abort () at /lib/libc.so.6
#2  0x00007fffed08ec50 in __libc_message () at /lib/libc.so.6
#3  0x00007fffed094fe6 in malloc_printerr () at /lib/libc.so.6
#4  0x00007fffed09536c in malloc_consolidate () at /lib/libc.so.6
#5  0x00007fffed096d2a in _int_malloc () at /lib/libc.so.6
#6  0x00007fffed098d44 in malloc () at /lib/libc.so.6
#7  0x00007fffed966a78 in operator new(unsigned long) (sz=8192) at /build/gcc-multilib/src/gcc/libstdc++-v3/libsupc++/new_op.cc:50
#8  0x00007fffeed3d684 in cv::putText(cv::_InputOutputArray const&, cv::String const&, cv::Point_<int>, int, double, cv::Scalar_<double>, int, int, bool) ()
    at /usr/local/lib/libopencv_imgproc.so.3.1
#9  0x00000000004a951b in main(int, char**) (argc=4, argv=0x7fffffffe0d8) at /home/andro/stypevisualirtracker/examples/videoGTKExample.cpp:180

从此question

  

abort()向调用进程发送SIGABRT信号,这是怎么回事   abort()基本上有效。

     

abort()通常由检测a的库函数调用   内部错误或一些严重破坏的约束。例如   如果内部结构被a损坏,malloc()将调用abort()   堆溢出。

所以这肯定是由损坏的堆引起的。

0 个答案:

没有答案