From f0b384028bf6183696d473cec8f2a449eaf2edde Mon Sep 17 00:00:00 2001 From: Andriy Utkin Date: Fri, 6 Dec 2024 02:03:59 +0000 Subject: [PATCH] server/motion_processor.cpp: fix crash by freeing cv::Mat the right way This happens when schedule changes from 'M' to 'C'. This is how it looks in the logs: I(1/software): motion_blend_radio is set to 15:1 I(1/software): motion_debug is set to 0 I(1/software): Motion detected E(): Got connection, but failed to accept I(1/software): Switching to new recording schedule 'continuous' BUG: Segment violation at 0x0000000000000366 Call trace: [0x000055db84eb8d5b] @ /usr/sbin/bc-server [0x00007f9949977320] @ /lib/x86_64-linux-gnu/libc.so.6 [0x00007f994a5c77e9] _ZN2cv3Mat7releaseEv+0x00000000 @ /lib/x86_64-linux-gnu/libopencv_core.so.406 [0x000055db84eb8ee4] @ /usr/sbin/bc-server [0x000055db84ebc2d6] @ /usr/sbin/bc-server [0x000055db84ebc8dd] @ /usr/sbin/bc-server [0x00007f99499cea94] @ /lib/x86_64-linux-gnu/libc.so.6 [0x00007f9949a5ba34] __clone+0x00000000 @ /lib/x86_64-linux-gnu/libc.so.6 This is how it looks in the debugger: #0 0x00007f994a5c77e9 in cv::Mat::release() () from /lib/x86_64-linux-gnu/libopencv_core.so.406 #1 0x000055db84eb8ee4 in motion_processor::~motion_processor (this=0x7f993000bbb0, __in_chrg=) at motion_processor.cpp:59 #2 0x000055db84ebc2d6 in motion_processor::~motion_processor (this=0x7f993000bbb0, __in_chrg=) at motion_processor.cpp:42 #3 motion_processor::run (this=0x7f993000bbb0) at motion_processor.cpp:201 #4 0x000055db84ebc8dd in bc_mproc_thread (data=) at motion_processor.cpp:861 #5 0x00007f99499cea94 in start_thread (arg=) at ./nptl/pthread_create.c:447 #6 0x00007f9949a5ba34 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100 According to the documentation, cv::Mat automatically derefs and frees data as needed on being destroyed (e.g. delete) https://docs.opencv.org/4.x/d3/d63/classcv_1_1Mat.html#ae48d4913285518e2c21a3457017e716e The bug was introduced by a memory leak fix. Fixes: 089e6de08de8 ("motion_processor: release cv::Mat objects") --- server/motion_processor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/motion_processor.cpp b/server/motion_processor.cpp index fa6fb7d3..d55b450b 100644 --- a/server/motion_processor.cpp +++ b/server/motion_processor.cpp @@ -37,6 +37,10 @@ motion_processor::motion_processor(bc_record *bcRecord) memset(&m_debugEventTime, 0, sizeof(struct tm)); m_debugEventTime.tm_sec = -1; + + // m_refFrames[2] is a static array so ctors, dtors are not called automatically on elements + new(&m_refFrames[0]) cv::Mat(); + new(&m_refFrames[1]) cv::Mat(); } motion_processor::~motion_processor() @@ -55,9 +59,9 @@ motion_processor::~motion_processor() } #endif - for (int i = 0; i < sizeof(m_refFrames); i++) { - m_refFrames[i].release(); - } + // m_refFrames[2] is a static array so ctors, dtors are not called automatically on elements + m_refFrames[0].~Mat(); + m_refFrames[1].~Mat(); delete output_source; } @@ -579,7 +583,6 @@ int motion_processor::detect_opencv(AVFrame *rawFrame) // first things first... get the original frame from the AVFrame and convert it to an OpenCV Grayscale Mat, and the "downscale" size. cv::Mat m = cv::Mat(dst_h, dst_w, CV_8UC1); if (convert_AVFrame_to_grayMat(rawFrame, m) == 0) { - m.release(); return 0; // error converting frame... } @@ -620,7 +623,6 @@ int motion_processor::detect_opencv(AVFrame *rawFrame) if (m_motionDebug) check_for_new_debug_event(ret); - m.release(); return ret; } @@ -633,7 +635,6 @@ int motion_processor::detect_opencv_advanced(AVFrame *rawFrame) // first things first... get the original frame from the AVFrame and convert it to an OpenCV Grayscale Mat, and the "downscale" size. cv::Mat m = cv::Mat(dst_h, dst_w, CV_8UC1); if (convert_AVFrame_to_grayMat(rawFrame, m) == 0) { - m.release(); return 0; // error converting frame... } @@ -669,7 +670,6 @@ int motion_processor::detect_opencv_advanced(AVFrame *rawFrame) } m_motionTriggered = (num_md_frames >= m_minMotionFrames); - m.release(); return m_motionTriggered; }