加入星計(jì)劃,您可以享受以下權(quán)益:

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

嵌入式開發(fā)調(diào)試?yán)?| Sanitizer檢測器

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

大家好,我是雜燴君。本次我們來分享一個(gè)開發(fā)調(diào)試?yán)鳌猄anitizer。

Sanitizer簡介

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

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

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

Sanitizer使用

1、AddressSanitizer的使用例子

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

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

AddressSanitizer.c:

//?微信公眾號(hào):嵌入式大雜燴
#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;
}

編譯、運(yùn)行:

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

執(zhí)行結(jié)果分析:

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

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

ThreadSanitizer.c:

//?微信公眾號(hào):嵌入式大雜燴
#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) 是一個(gè)數(shù)據(jù)競爭檢測器,可以用來分析線程競態(tài)、死鎖等線程相關(guān)問題。編譯時(shí)帶上參數(shù) -fsanitize=thread及-g。

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

//?微信公眾號(hào):嵌入式大雜燴
#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;
}

編譯、運(yùn)行:

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

執(zhí)行結(jié)果分析:

觸發(fā)了檢測警告級(jí)別,程序仍能運(yùn)行,并給出了程序運(yùn)行有風(fēng)險(xiǎn)的原因及有風(fēng)險(xiǎn)的代碼位置。

3、程序中同時(shí)存在多處風(fēng)險(xiǎn)?

上面的例子分別使用AddressSanitizer檢測器與ThreadSanitizer檢測器來檢測對(duì)應(yīng)的異常,可以較為精準(zhǔn)地檢測到對(duì)應(yīng)的異常。

如果程序中同時(shí)存在多處風(fēng)險(xiǎn)呢?

這也是比較貼近我們的實(shí)際應(yīng)用的,畢竟我們并不知道我們的代碼里有哪些可能存在的風(fēng)險(xiǎn)。這種情況我們要怎么檢測?

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

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

AddressSanitizer與ThreadSanitizer檢測器不能同時(shí)使用。

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

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

test.c:

//?微信公眾號(hào):嵌入式大雜燴
#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ù)編譯、運(yùn)行:

執(zhí)行結(jié)果分析:

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

是不是因?yàn)閠est_func2運(yùn)行在test_func1后面了,所以test_func2的異常沒有被ThreadSanitizer檢測器檢測出來?

我們調(diào)換個(gè)位置看看:

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

????return?0;
}

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

所以,大致得出結(jié)論:當(dāng)程序里存在thread異常與address異常時(shí),使用ThreadSanitizer檢測器能準(zhǔn)確檢測到thread異常,能檢測到部分address異常。

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

執(zhí)行順序:

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

????return?0;
}

執(zhí)行結(jié)果分析:

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

結(jié)論:當(dāng)程序里存在thread異常與address異常時(shí),使用AddressSanitizer檢測器能準(zhǔn)確檢測到第一個(gè)觸發(fā)的address異常,不能檢測到thread異常。

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

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

碼字不易,如果文章對(duì)你有幫助,麻煩幫忙點(diǎn)贊、關(guān)注,謝謝大家!

推薦器件

更多器件
器件型號(hào) 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險(xiǎn)等級(jí) 參考價(jià)格 更多信息
SN74LVC2T45DCUR 1 Texas Instruments 2-Bit Dual Supply Transceiver with Configurable Voltage-Level Shifting and 3-State Outputs 8-VSSOP -40 to 85

ECAD模型

下載ECAD模型
$0.79 查看
AFBR-57R5APZ 1 Agilent Technologies Inc Fiber Optic Device
$40.94 查看
MOC3021SR2M 1 Rochester Electronics LLC 1 CHANNEL TRIAC OUTPUT OPTOCOUPLER, SURFACE MOUNT, DIP-6
$0.68 查看

相關(guān)推薦

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

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