加入星計劃,您可以享受以下權益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
  • 推薦器件
  • 相關推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式開發(fā)調試利器 | Sanitizer檢測器

04/07 15:38
2754
閱讀需 14 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

大家好,我是雜燴君。本次我們來分享一個開發(fā)調試利器——Sanitizer。

Sanitizer簡介

Sanitizer是由Google發(fā)起的開源工具集,用于檢測內(nèi)存泄露等問題。

鏈接:https://github.com/google/sanitizers/wiki/

它包括了AddressSanitizer、MemorySanitizer、ThreadSanitizer、LeakSanitizer等多種工具。這些工具最初是LLVM項目的一部分,后來也被GNU的GCC編譯器支持。從GCC的4.8版本開始,就已經(jīng)支持AddressSanitizer和ThreadSanitizer,而4.9版本則開始支持LeakSanitizer。

Sanitizer使用

1、AddressSanitizer的使用例子

AddressSanitizer(ASan) 是一個快速內(nèi)存檢測器,可以檢測出緩沖區(qū)溢出、使用已釋放內(nèi)存等問題。編譯時帶上參數(shù) -fsanitize=address及-g。

(1)捕捉棧緩沖區(qū)溢出問題:

AddressSanitizer.c:

//?微信公眾號:嵌入式大雜燴
#include?<stdlib.h>

void?test_func(void)
{
????int?a[6]?=?{0};
????int?b?=?a[6];????//?棧緩沖區(qū)溢出
}?????????????????????

int?main(int?argc,?char?**argv)
{
?test_func();

?return?0;
}

編譯、運行:

gcc?AddressSanitizer.c?-fsanitize=address?-g?-o?AddressSanitizer

執(zhí)行結果分析:

觸發(fā)了檢測錯誤級別,終止程序并給出了程序運行異常的原因及異常的代碼位置。

(2)捕捉使用已釋放內(nèi)存問題:

ThreadSanitizer.c:

//?微信公眾號:嵌入式大雜燴
#include?<stdlib.h>

void?test_func(void)
{
????char?*p?=?malloc(10);
????p[0]?=?1;
????free(p);
????p[0]?=?1;??//?使用已釋放內(nèi)存
}?????????????????????

int?main(int?argc,?char?**argv)
{
?test_func();

?return?0;
}

2、ThreadSanitizer的使用例子

ThreadSanitizer(TSan) 是一個數(shù)據(jù)競爭檢測器,可以用來分析線程競態(tài)、死鎖等線程相關問題。編譯時帶上參數(shù) -fsanitize=thread及-g。

捕捉 線程間數(shù)據(jù)競爭 問題:

//?微信公眾號:嵌入式大雜燴
#include?<stdio.h>
#include?<pthread.h>

int?g_counter?=?0;??//?thread1、thread2競爭的數(shù)據(jù)

void?*increment(void?*arg)
{
????g_counter++;
}

void?*decrement(void?*arg)
{
????g_counter--;
}

void?test_func(void)
{
????pthread_t?thread1,?thread2;

????pthread_create(&thread1,?NULL,?increment,?NULL);
????pthread_create(&thread2,?NULL,?decrement,?NULL);

????pthread_join(thread1,?NULL);
????pthread_join(thread2,?NULL);

????printf("Counter?value:?%dn",?g_counter);
}

int?main(int?argc,?char?**argv)
{
????test_func();

????return?0;
}

編譯、運行:

gcc?ThreadSanitizer.c?-fsanitize=thread?-g?-pthread?-o?ThreadSanitizer

執(zhí)行結果分析:

觸發(fā)了檢測警告級別,程序仍能運行,并給出了程序運行有風險的原因及有風險的代碼位置。

3、程序中同時存在多處風險?

上面的例子分別使用AddressSanitizer檢測器與ThreadSanitizer檢測器來檢測對應的異常,可以較為精準地檢測到對應的異常。

如果程序中同時存在多處風險呢?

這也是比較貼近我們的實際應用的,畢竟我們并不知道我們的代碼里有哪些可能存在的風險。這種情況我們要怎么檢測?

編譯時能同時帶上多個-fsanitize參數(shù)調用多個檢測器嗎?

可以同時帶,但有些檢測器不能同時使用。

AddressSanitizer與ThreadSanitizer檢測器不能同時使用。

但是,假如我們的程序中恰好存在address異常與thread異常呢,單獨使用AddressSanitizer檢測器、ThreadSanitizer檢測器的表現(xiàn)是怎樣的?

比如,我們把上面3個例子的代碼放在一起:

test.c:

//?微信公眾號:嵌入式大雜燴
#include?<stdio.h>
#include?<stdlib.h>
#include?<pthread.h>

int?g_counter?=?0;??//?thread1、thread2競爭的數(shù)據(jù)

void?*increment(void?*arg)
{
????g_counter++;
}

void?*decrement(void?*arg)
{
????g_counter--;
}

//?測試:資源競爭
void?test_func(void)
{
????pthread_t?thread1,?thread2;

????pthread_create(&thread1,?NULL,?increment,?NULL);
????pthread_create(&thread2,?NULL,?decrement,?NULL);

????pthread_join(thread1,?NULL);
????pthread_join(thread2,?NULL);

????printf("Counter?value:?%dn",?g_counter);
}

//?測試:使用已釋放內(nèi)存
void?test_func1(void)
{
????char?*p?=?malloc(10);

????printf("This?is?test_func1n");

????p[0]?=?1;
????free(p);
????p[0]?=?1;??//?使用已釋放內(nèi)存
}?????

//?測試:棧緩沖區(qū)溢出
void?test_func2(void)
{
????int?a[6]?=?{0};
????int?b?=?a[6];????//?棧緩沖區(qū)溢出
}?????

int?main(int?argc,?char?**argv)
{
????test_func();
????test_func1();
?test_func2();

????return?0;
}

帶-fsanitize=thread參數(shù)編譯、運行:

執(zhí)行結果分析:

ThreadSanitizer檢測器能正常檢測出資源競爭的問題,也檢測出了test_func1中的使用已釋放的堆內(nèi)存的問題并以警告級別報告,但沒有檢測出test_func2的棧緩沖區(qū)溢出問題。

是不是因為test_func2運行在test_func1后面了,所以test_func2的異常沒有被ThreadSanitizer檢測器檢測出來?

我們調換個位置看看:

int?main(int?argc,?char?**argv)
{
????test_func();
?test_func2();
????test_func1();

????return?0;
}

顯然,執(zhí)行結果還是一樣的,test_func2的棧緩沖區(qū)溢出問題還是沒有被ThreadSanitizer檢測器檢測出來。

所以,大致得出結論:當程序里存在thread異常與address異常時,使用ThreadSanitizer檢測器能準確檢測到thread異常,能檢測到部分address異常。

帶-fsanitize=address參數(shù)編譯、運行:

執(zhí)行順序:

int?main(int?argc,?char?**argv)
{
????test_func();
????test_func1();
????test_func2();

????return?0;
}

執(zhí)行結果分析:

AddressSanitizer檢測器檢測到了test_func1中的已使用釋放的堆內(nèi)存的異常并以錯誤級別報告,并終止了程序;沒有檢測到test_func的資源競爭的風險;也沒有檢測到test_func2的棧緩沖區(qū)溢出的問題,因為執(zhí)行到test_func1的時候程序已經(jīng)被終止了,如果把test_func2放在test_func1之前運行,就能檢測到test_func2的異常。

結論:當程序里存在thread異常與address異常時,使用AddressSanitizer檢測器能準確檢測到第一個觸發(fā)的address異常,不能檢測到thread異常。

如果程序中存在多種可能存在的風險時,需要使用多個檢測器單獨挨個檢測。每個檢測器都有其擅長檢測的方面,可以經(jīng)過初步分析之后確定大致地方向,選擇適合地檢測器來做檢測。

以上就是關于Sanitizer的一些簡單介紹及使用的分享,更多的關于Sanitizer的資料可查閱:https://github.com/google/sanitizers/wiki/

碼字不易,如果文章對你有幫助,麻煩幫忙點贊、關注,謝謝大家!

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
PBRC16.00HR50X000 1 Kyocera AVX Components Ceramic Resonator, 16MHz Nom, ROHS COMPLIANT, SMALL, CERAMIC, SMD, 3 PIN
$1.2 查看
CSTLS4M00G53-B0 1 Murata Manufacturing Co Ltd Ceramic Resonator, 4MHz Nom, CERAMIC PACKAGE-3

ECAD模型

下載ECAD模型
$0.43 查看
IL420-X007T 1 Vishay Intertechnologies Optocoupler Triac AC-OUT 1-CH 600VDRM 6-Pin PDIP SMD T/R
$4.61 查看

相關推薦

電子產(chǎn)業(yè)圖譜

本公眾號專注于嵌入式技術,包括但不限于C/C++、嵌入式、物聯(lián)網(wǎng)、Linux等編程學習筆記,同時,公眾號內(nèi)包含大量的學習資源。歡迎關注,一同交流學習,共同進步!