嵌入式代码的debug一直是一个比较麻烦的问题,这些代码通常无法在本地PC调试,而在开发板上显示的错误有时又太过简单(例如经典的Segmentation Fault和Bus Error),无法追溯到错误的具体位置,有时甚至都不会报错,程序就莫名其妙的中断了。
这里提供一个非常好用的解决办法,就是在你的编译选项中加入下列内容:
-fsanitize=address -fno-omit-frame-pointer
加入后,原本的CMake就变成了下面的样子。
# set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wall -O1")
# set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -O1 -std=c++11 -fPIC")
//增加编译选项
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wall -O1 -g -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wall -O1 -g -fsanitize=address -fno-omit-frame-pointer -std=c++11 -fPIC")
修改CMake后,重新编译,将生成的程序发送到开发板。这样,在程序运行时,就会自动追踪代码崩溃的位置,以及错误的类型。
这是我追踪到的崩溃分析log:
=================================================================
==8985==ERROR: AddressSanitizer: heap-use-after-free on address 0x7f40a59354 at pc 0x7f7c782d34 bp 0x7fe915b480 sp 0x7fe915b4e8
READ of size 2400 at 0x7f40a59354 thread T0
#0 0x7f7c782d33 in __interceptor_memcpy.part.44 (/usr/lib64/libasan.so.3+0x66d33)
#1 0x7f7bb4dd8f (/usr/lib/libQt5Gui.so.5+0x336d8f)
0x7f40a59354 is located 342868 bytes inside of 3686400-byte region [0x7f40a05800,0x7f40d89800)
freed by thread T20 (QThread) here:
#0 0x7f7c7b41a7 in __interceptor_free (/usr/lib64/libasan.so.3+0x981a7)
#1 0x7f7b972457 in QImageData::~QImageData() (/usr/lib/libQt5Gui.so.5+0x15b457)
#2 0x7f7b9726f3 in QImage::~QImage() (/usr/lib/libQt5Gui.so.5+0x15b6f3)
#3 0x7f7b9ac323 in QRasterPlatformPixmap::~QRasterPlatformPixmap() (/usr/lib/libQt5Gui.so.5+0x195323)
#4 0x7f7b9ac34b in QRasterPlatformPixmap::~QRasterPlatformPixmap() (/usr/lib/libQt5Gui.so.5+0x19534b)
#5 0x7f7b9a38f3 in QPixmap::~QPixmap() (/usr/lib/libQt5Gui.so.5+0x18c8f3)
#6 0x7f7b9a391b in QPixmap::~QPixmap() (/usr/lib/libQt5Gui.so.5+0x18c91b)
#7 0x7f7b2fbf63 (/usr/lib/libQt5Widgets.so.5+0x2baf63)
#8 0x7f7b2fdbef in QLabel::setPixmap(QPixmap const&) (/usr/lib/libQt5Widgets.so.5+0x2bcbef)
#9 0x514d17 in FRAtd::readframe() /home/260243/gz/2020/yunding_qt/FRAS/src/fratd.cpp:266
#10 0x581f77 in FRAtd::qt_static_metacall(QObject*, QmetaObject::Call, int, void**) /home/260243/gz/2020/yunding_qt/FRAS/build/headers/moc_fratd.cpp:158
#11 0x7f7bf9288f in QmetaObject::activate(QObject*, int, int, void**) (/usr/lib/libQt5Core.so.5+0x2b188f)
#12 0x7f7bf9f2bb in QTimer::timeout(QTimer::QPrivateSignal) (/usr/lib/libQt5Core.so.5+0x2be2bb)
#13 0x7f7bf9f653 in QTimer::timerEvent(QTimerEvent*) (/usr/lib/libQt5Core.so.5+0x2be653)
#14 0x7f7bf932ab in QObject::event(QEvent*) (/usr/lib/libQt5Core.so.5+0x2b22ab)
#15 0x7f7b1ca083 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x189083)
#16 0x7f7b1d0227 in QApplication::notify(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x18f227)
#17 0x7f7bf64f53 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (/usr/lib/libQt5Core.so.5+0x283f53)
#18 0x7f7bfbd7ef in QTimerInfoList::activateTimers() (/usr/lib/libQt5Core.so.5+0x2dc7ef)
#19 0x7f7bfbe087 (/usr/lib/libQt5Core.so.5+0x2dd087)
#20 0x7f79ff1ba7 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x42ba7)
#21 0x7f79ff1deb (/usr/lib/libglib-2.0.so.0+0x42deb)
#22 0x7f79ff1eb7 in g_main_context_iteration (/usr/lib/libglib-2.0.so.0+0x42eb7)
#23 0x7f7bfbe37f in QEventDispatcherGlib::processEvents(QFlags) (/usr/lib/libQt5Core.so.5+0x2dd37f)
#24 0x7f7bf63673 in QEventLoop::exec(QFlags) (/usr/lib/libQt5Core.so.5+0x282673)
#25 0x7f7bd9f5e7 in QThread::exec() (/usr/lib/libQt5Core.so.5+0xbe5e7)
#26 0x7f7bda0c23 (/usr/lib/libQt5Core.so.5+0xbfc23)
#27 0x7f7c3459d7 in start_thread (/lib/libpthread.so.0+0x79d7)
#28 0x7f7a20b12b (/lib/libc.so.6+0xcb12b)
previously allocated by thread T20 (QThread) here:
#0 0x7f7c7b445f in __interceptor_malloc (/usr/lib64/libasan.so.3+0x9845f)
#1 0x7f7b972ba7 in QImageData::create(QSize const&, QImage::Format) (/usr/lib/libQt5Gui.so.5+0x15bba7)
#2 0x7f7b972d1b in QImage::QImage(QSize const&, QImage::Format) (/usr/lib/libQt5Gui.so.5+0x15bd1b)
#3 0x7f7b972d47 in QImage::QImage(int, int, QImage::Format) (/usr/lib/libQt5Gui.so.5+0x15bd47)
#4 0x7f7b975b6b in QImage::convertToFormat_helper(QImage::Format, QFlags) const (/usr/lib/libQt5Gui.so.5+0x15eb6b)
#5 0x7f7b9acd5f in QRasterPlatformPixmap::createPixmapForImage(QImage, QFlags) (/usr/lib/libQt5Gui.so.5+0x195d5f)
#6 0x7f7b9ace6f in QRasterPlatformPixmap::fromImage(QImage const&, QFlags) (/usr/lib/libQt5Gui.so.5+0x195e6f)
#7 0x7f7b9a32bf in QPixmap::fromImage(QImage const&, QFlags) (/usr/lib/libQt5Gui.so.5+0x18c2bf)
#8 0x514d0b in FRAtd::readframe() /home/260243/gz/2020/yunding_qt/FRAS/src/fratd.cpp:266
#9 0x581f77 in FRAtd::qt_static_metacall(QObject*, QmetaObject::Call, int, void**) /home/260243/gz/2020/yunding_qt/FRAS/build/headers/moc_fratd.cpp:158
#10 0x7f7bf9288f in QmetaObject::activate(QObject*, int, int, void**) (/usr/lib/libQt5Core.so.5+0x2b188f)
#11 0x7f7bf9f2bb in QTimer::timeout(QTimer::QPrivateSignal) (/usr/lib/libQt5Core.so.5+0x2be2bb)
#12 0x7f7bf9f653 in QTimer::timerEvent(QTimerEvent*) (/usr/lib/libQt5Core.so.5+0x2be653)
#13 0x7f7bf932ab in QObject::event(QEvent*) (/usr/lib/libQt5Core.so.5+0x2b22ab)
#14 0x7f7b1ca083 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x189083)
#15 0x7f7b1d0227 in QApplication::notify(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x18f227)
#16 0x7f7bf64f53 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (/usr/lib/libQt5Core.so.5+0x283f53)
#17 0x7f7bfbd7ef in QTimerInfoList::activateTimers() (/usr/lib/libQt5Core.so.5+0x2dc7ef)
#18 0x7f7bfbe087 (/usr/lib/libQt5Core.so.5+0x2dd087)
#19 0x7f79ff1ba7 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x42ba7)
#20 0x7f79ff1deb (/usr/lib/libglib-2.0.so.0+0x42deb)
#21 0x7f79ff1eb7 in g_main_context_iteration (/usr/lib/libglib-2.0.so.0+0x42eb7)
#22 0x7f7bfbe37f in QEventDispatcherGlib::processEvents(QFlags) (/usr/lib/libQt5Core.so.5+0x2dd37f)
#23 0x7f7bf63673 in QEventLoop::exec(QFlags) (/usr/lib/libQt5Core.so.5+0x282673)
#24 0x7f7bd9f5e7 in QThread::exec() (/usr/lib/libQt5Core.so.5+0xbe5e7)
#25 0x7f7bda0c23 (/usr/lib/libQt5Core.so.5+0xbfc23)
#26 0x7f7c3459d7 in start_thread (/lib/libpthread.so.0+0x79d7)
#27 0x7f7a20b12b (/lib/libc.so.6+0xcb12b)
Thread T20 (QThread) created by T0 here:
#0 0x7f7c745e9f in __interceptor_pthread_create (/usr/lib64/libasan.so.3+0x29e9f)
#1 0x7f7bda039f in QThread::start(QThread::Priority) (/usr/lib/libQt5Core.so.5+0xbf39f)
#2 0x513a57 in FRAtd::initThread(QThread*, QTimer*, char const*, int) /home/260243/gz/2020/yunding_qt/FRAS/src/fratd.cpp:242
#3 0x517d9b in FRAtd::FRAtd(QDialog*) /home/260243/gz/2020/yunding_qt/FRAS/src/fratd.cpp:109
#4 0x53c8d3 in ScreenSaver::toFRAtd() /home/260243/gz/2020/yunding_qt/FRAS/src/screensaver.cpp:183
#5 0x53cb2b in ScreenSaver::backlightSlot() /home/260243/gz/2020/yunding_qt/FRAS/src/screensaver.cpp:204
#6 0x58bd97 in ScreenSaver::qt_static_metacall(QObject*, QmetaObject::Call, int, void**) /home/260243/gz/2020/yunding_qt/FRAS/build/headers/moc_screensaver.cpp:150
#7 0x7f7bf9288f in QmetaObject::activate(QObject*, int, int, void**) (/usr/lib/libQt5Core.so.5+0x2b188f)
#8 0x7f7bf9f2bb in QTimer::timeout(QTimer::QPrivateSignal) (/usr/lib/libQt5Core.so.5+0x2be2bb)
#9 0x7f7bf9f653 in QTimer::timerEvent(QTimerEvent*) (/usr/lib/libQt5Core.so.5+0x2be653)
#10 0x7f7bf932ab in QObject::event(QEvent*) (/usr/lib/libQt5Core.so.5+0x2b22ab)
#11 0x7f7b1ca083 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x189083)
#12 0x7f7b1d0227 in QApplication::notify(QObject*, QEvent*) (/usr/lib/libQt5Widgets.so.5+0x18f227)
#13 0x7f7bf64f53 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (/usr/lib/libQt5Core.so.5+0x283f53)
#14 0x7f7bfbd7ef in QTimerInfoList::activateTimers() (/usr/lib/libQt5Core.so.5+0x2dc7ef)
#15 0x7f7bfbe087 (/usr/lib/libQt5Core.so.5+0x2dd087)
#16 0x7f79ff1ba7 in g_main_context_dispatch (/usr/lib/libglib-2.0.so.0+0x42ba7)
#17 0x7f79ff1deb (/usr/lib/libglib-2.0.so.0+0x42deb)
#18 0x7f79ff1eb7 in g_main_context_iteration (/usr/lib/libglib-2.0.so.0+0x42eb7)
#19 0x7f7bfbe37f in QEventDispatcherGlib::processEvents(QFlags) (/usr/lib/libQt5Core.so.5+0x2dd37f)
#20 0x7f7bf63673 in QEventLoop::exec(QFlags) (/usr/lib/libQt5Core.so.5+0x282673)
#21 0x7f7bf6c18f in QCoreApplication::exec() (/usr/lib/libQt5Core.so.5+0x28b18f)
#22 0x428d0b in main /home/260243/gz/2020/yunding_qt/FRAS/main.cpp:124
#23 0x7f7a160c1f in __libc_start_main (/lib/libc.so.6+0x20c1f)
#24 0x428283 (/userdata/FRAS/FRAS+0x428283)
SUMMARY: AddressSanitizer: heap-use-after-free (/usr/lib64/libasan.so.3+0x66d33) in __interceptor_memcpy.part.44
Shadow bytes around the buggy address:
0x1fe814b210: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b220: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b230: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b240: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b250: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x1fe814b260: fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd fd
0x1fe814b270: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b280: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b290: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b2a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1fe814b2b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==8985==ABORTING
通过这份log,我们可以清楚的看到,崩溃的原因是:heap-use-after-free,即堆溢出。代码发生错误的位置是在一个线程中,调用一个函数时,QPixmap的析构引发了错误。
如果不加这行编译选项,那么程序就会直接崩溃,不报任何错误,这样排查问题就非常棘手了。
此外,编译选项还会发现一些隐藏的内存问题,这些问题可能已被某一环节优化,并不会导致程序出现任何的异常,但编译选项还是严格地找出了它们并中断程序,建议最好还是按照编译选项的报错修改代码,养成好习惯。
加入编译选项也会带来一些副作用,例如编译时间变长、可执行程序变大、程序运行变慢等等,因此在release版本中请去掉此编译选项。



