使用 Clang 进行动态分析 - 抑制在 CMake 项目中忽略的外部库中的报告

Dynamic Analysis with Clang - Suppressing Reports in External Libraries Ignored in a CMake project

我正在尝试在 clang 编译器中使用 -fsanitize=address feature,但我只想查看本地项目错误,因此我将忽略来自 3rdparty 库的传入错误,特别是我有一个项目被配置为忽略来自 dbus 的错误。

我的系统: cmake 版本 3.9.5

Linux 主机名 4.14.0-2-amd64 #1 SMP Debian 4.14.7-1 (2017-12-22) x86_64 GNU/Linux

clang 版本 4.0.1-8 (tags/RELEASE_401/final) 目标:x86_64-pc-linux-gnu 线程模型:posix 安装目录:/usr/bin

我的mcve:

.
├── CMakeLists.txt
├── CTestConfig.cmake
├── CTestCustom.cmake
├── MyASan.supp
└── src
    ├── CMakeLists.txt
    ├── entityitem.cc
    ├── mainwindow.cc
    ├── mainwindow.h
    └── mainwindow.ui

1 directory, 10 files

CMakeLists.txt:

cmake_minimum_required(VERSION 3.9.0 FATAL_ERROR)
project(SanitizerTest)
set(CMAKE_C_STANDARD 14)
set(CMAKE_CXX_STANDARD 14)
include(CTest)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src)

CTestConfig.cmake:

## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
##
## # The following are required to submit to the CDash dashboard:
##   ENABLE_TESTING()
##   INCLUDE(CTest)

set(CTEST_PROJECT_NAME "Exampling")
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")

set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "localhost:8090")
set(CTEST_DROP_LOCATION "/submit.php?project=Exampling")
set(CTEST_DROP_SITE_CDASH TRUE)

CTestCustom.cmake:

set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer")
set(CTEST_SOURCE_DIRECTORY ${CTEST_SCRIPT_DIRECTORY})
set(CTEST_MEMORYCHECK_SUPPRESSIONS_FILE ${CTEST_SOURCE_DIRECTORY}/MyASan.supp)
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer")
ctest_start(Experimental)
set(CONFIGURE_OPTIONS
  "-DCMAKE_BUILD_TYPE=Debug"
  "-DCMAKE_CXX_FLAGS=-g -O0 -fno-omit-frame-pointer -fsanitize=address"
  "-DCMAKE_C_FLAGS=-g -O0 -fno-omit-frame-pointer -fsanitize=address"
  "-DCMAKE_GENERATOR=Unix Makefiles"
  "-DCMAKE_CXX_COMPILER=clang"
  "-DCMAKE_C_COMPILER=clang"
)
ctest_configure(OPTIONS "${CONFIGURE_OPTIONS}")
ctest_build()

MyASan.supp:

interceptor_via_lib:dbus-1

src/CMakeLists.txt:

find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
add_library(module
  ${CMAKE_CURRENT_SOURCE_DIR}/mainwindow.cc)
target_include_directories(module INTERFACE
  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/module_autogen/include>)
target_link_libraries(module
  PUBLIC stdc++
  PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets)
add_executable(main
  ${CMAKE_CURRENT_SOURCE_DIR}/entityitem.cc)
target_link_libraries(main module)

src/entityitem.cc:

#include <QtWidgets/QApplication>
#include <QtCore/QDebug>
#include "mainwindow.h"
int main(int argc, char *argv[]) {
  QApplication a{argc, argv};
  MainWindow d;
  qDebug() << d.width();
  return EXIT_SUCCESS;
}

src/mainwindow.cc:

#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
  int *i{new int};
  ui.setupUi(this);
}

src/mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_mainwindow.h"
class MainWindow : public QMainWindow {
    Q_OBJECT
  public:
    explicit MainWindow(QWidget *parent = 0);
  private:
    Ui::MainWindow ui;
};
#endif // MAINWINDOW_H

src/mainwindow.ui:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>400</width>
    <height>300</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralWidget"/>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>400</width>
     <height>30</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

我的问题,从项目根目录执行:

mkdir build
cd build
ctest -DCTEST_BINARY_DIRECTORY="." --verbose -S ../CTestCustom.cmake
./src/main

然后输出是:

    =================================================================
    ==24262==ERROR: LeakSanitizer: detected memory leaks

    Direct leak of 6912 byte(s) in 27 object(s) allocated from:
        #0 0x4d0810  (/home/adacosta/WORK/fffffffffff/Sanitazer/build/src/main+0x4d0810)
        #1 0x7f75480378ed  (/usr/lib/x86_64-linux-gnu/libfontconfig.so.1+0x1d8ed)

    Direct leak of 4 byte(s) in 1 object(s) allocated from:
        #0 0x4d0810  (/home/adacosta/WORK/fffffffffff/Sanitazer/build/src/main+0x4d0810)
        #1 0x7f75529b1097  (/usr/lib/x86_64-linux-gnu/libstdc++.so.6+0x90097)
        #2 0x50a80f  (/home/adacosta/WORK/fffffffffff/Sanitazer/build/src/main+0x50a80f)
        #3 0x7f7550369f29  (/lib/x86_64-linux-gnu/libc.so.6+0x20f29)

    Indirect leak of 4239 byte(s) in 5 object(s) allocated from:
        #0 0x4d0c35  (/home/adacosta/WORK/fffffffffff/Sanitazer/build/src/main+0x4d0c35)
        #1 0x7f754545b47c  (/lib/x86_64-linux-gnu/libdbus-1.so.3+0x3247c)

    Indirect leak of 1824 byte(s) in 57 object(s) allocated from:
        #0 0x4d0a18  (/home/adacosta/WORK/fffffffffff/Sanitazer/build/src/main+0x4d0a18)
        #1 0x7f7548037fd8  (/usr/lib/x86_64-linux-gnu/libfontconfig.so.1+0x1dfd8)
.
.
.

如您所见,我有一个来自 dbus 库的 "Indirect leak of"。

解决方案:

  1. set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer")改为 set(CTEST_MEMORYCHECK_TYPE "LeakSanitizer")
  2. interceptor_via_lib:dbus-1 更改为 leak:libdbus-1

这将发送 LSAN_OPTIONS 而不是 ASAN_OPTIONS 到进程执行。

更多信息:https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer#suppressions