<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

嵌入式代碼安全檢查:選擇if還是assert?

strongerHuang ? 來源:IOT物聯網小鎮 ? 2024-04-13 11:45 ? 次閱讀

你們平時寫代碼時,有注意過代碼的安全問題嗎?那你們有做什么操作嗎?今天就給大家分享一下相關的內容。

一、前言

我們在擼代碼的時候,經常需要對代碼的安全性進行檢查,例如:

1. 指針是否為空?
2. 被除數是否為 0?
3. 函數調用的返回結果是否有效?

4. 打開一個文件是否成功?

對這一類的邊界條件進行檢查的手段,一般都是使用 if 或者 assert 斷言,無論使用哪一個,都可以達到檢查的目的。那么是否就意味著:這兩者可以隨便使用,想起來哪個就用哪個?

這篇小短文我們就來掰扯掰扯:在不同的場景下,到底是應該用 if,還是應該使用 assert 斷言?

寫這篇文章的時候,我想起了孔乙己老先生的那個問題:茴香豆的“茴”字有幾種寫法?

似乎我們沒有必要來糾結應該怎么選擇,因為都能夠實現想要的功能。以前我也是這么想的,但是,現在我不這么認為。

成為技術大牛、拿到更好的offer,也許就在這些細微之間就分出了勝負。

二、assert 斷言

剛才,我問了下旁邊的一位工作 5 年多的嵌入式開發者:if 和 assert 如何選擇?他說:assert 是干什么的?!

看來,有必要先簡單說一下 assert 斷言。

assert() 的原型是:

void assert(int expression);

1. 如果宏的參數求值結果為非零值,則不做任何操作(no action);
2. 如果宏的參數是零值,就打印診斷消息,然后調用abort()。

例如下面的代碼:


		
#include 
int my_div(int a, int b)
{
    assert(0 != b);
    return a / b;
}

1. 當 b 不為 0 時,assert 斷言什么都不做,程序往下執行;
2. 當 b 為 0 時,assert 斷言就打印錯誤信息,然后終止程序;

從功能上來說,assert(0 != b); 與下面的代碼等價:


		
if (0 == b)
{
    fprintf(stderr, "b is zero...");
    abort();
}

assert 是一個宏,不是一個函數

在 assert.h 頭文件中,有如下定義:


		
#ifdef NDEBUG
    #define assert(condition) ((void)0)
#else
    #define assert(condition) /*implementation defined*/
#endif

既然是宏定義,說明是在預處理的時候進行宏替換。(關于宏的更多內容,可以看一下這篇文章:提高代碼逼格的利器:宏定義-從入門到放棄)。

從上面的定義中可以看到:

  1. 如果定義了宏 NDEBUG,那么 assert() 宏將不做什么動作,也就是相當于一條空語句:(void)0;,當在 release 階段編譯代碼的時候,都會在編譯選項中(Makefile)定義這個宏。
  2. 如果沒有定義宏 NDEBUG,那么 assert() 宏將會把一些檢查代碼進行替換,我們在開發階段執行 debug 模式編譯時,一般都會屏蔽掉這 NDEBUG 這個宏。

三、if VS assert

還是以一個代碼片段來描述問題,以場景化來討論比較容易理解。


		
// brief: 把兩個短字符串拼接成一個字符串
char *my_concat(char *str1, char *str2)
{
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int len3 = len1 + len2;
    char *new_str = (char *)malloc(len3 + 1);
    memset(new_str, 0 len3 + 1);
    sprintf(new_str, "%s%s", str1, str2);
    return new_str;
}

如果一個開發人員寫出上面的代碼,一定會被領導約談的!它存在下面這些問題:

  1. 沒有對輸入參數進行有效性檢查;
  2. 沒有對 malloc 的結果進行檢查;
  3. sprintf 的效率很低;
  4. ...

1. 使用 if 語句來檢查


		
char *my_concat(char *str1, char *str2)
{
    if (!str1 || !str2)  // 參數錯誤
        return NULL;
        
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int len3 = len1 + len2;
    char *new_str = (char *)malloc(len3 + 1);
    
    if (!new_str)   // 申請堆空間失敗
        return NULL;
    
    memset(new_str, 0 len3 + 1);
    sprintf(new_str, "%s%s", str1, str2);
    return new_str;
}

2. 使用 assert 斷言來檢查


		
char *my_concat(char *str1, char *str2)
{
    // 確保參數正確
    assert(NULL != str1);
    assert(NULL != str2);
    
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int len3 = len1 + len2;
    char *new_str = (char *)malloc(len3 + 1);
    
    // 確保申請堆空間成功
    assert(NULL != new_str);
    
    memset(new_str, 0 len3 + 1);
    sprintf(new_str, "%s%s", str1, str2);
    return new_str;
}

3. 你喜歡哪一個?

首先聲明一點:以上這 2 種檢查方式,在實際的代碼中都很常見,從功能上來說似乎也沒有什么影響。因此,沒有嚴格的錯與對之分,很多都是依賴于每個人的偏好習慣不同而已。

(1) assert 支持者

我作為 my_concat() 函數的實現者,目的是拼接字符串,那么傳入的參數必須是合法有效的,調用者需要負責這件事。如果傳入的參數無效,我會表示十分的驚訝!怎么辦:崩潰給你看!

(2)if 支持者

我寫的 my_concat() 函數十分的健壯,我就預料到調用者會亂搞,故意的傳入一些無效參數,來測試我的編碼水平。沒事,來吧,我可以處理任何情況!

這兩個派別的理由似乎都很充足!那究竟該如何選擇?難道真的的跟著感覺走嗎?

假設我們嚴格按照常規的流程去開發一個項目:

1. 在開發階段,編譯選項中不定義 NDEBUG 這個宏,那么 assert 就發揮作用;
2. 項目發布時,編譯選項中定義了 NDEBUG 換個宏,那么 assert 就相當于空語句;

也就是說,只有在 debug 開發階段,用 assert 斷言才能夠正確的檢查到參數無效。而到了 release 階段,assert 不起作用,如果調用者傳遞了無效參數,那么程序只有崩潰的命運了。

這說明什么問題?是代碼中存在 bug?還是代碼寫的不夠健壯?

從我個人的理解上看,這壓根就是單元測試沒有寫好,沒有測出來參數無效的這個 case!

4. assert 的本質

assert 就是為了驗證有效性,它最大作用就是:在開發階段,讓我們的程序盡可能地 crash。每一次的 crash,都意味著代碼中存在著 bug,需要我們去修正。

當我們寫下一個 assert 斷言的時候,就說明:斷言失敗的這種情況是不可以的,是不被允許的。必須保證斷言成功,程序才能繼續往下執行。

5. if-else 的本質

if-else 語句用于邏輯處理,它是為了處理各種可能出現的情況。就是說:每一個分支都是合理的,是允許出現的,我們都要對這些分支進行處理。

6. 我喜歡的版本


		
char *my_concat(char *str1, char *str2)
{
    // 參數必須有效
    assert(NULL != str1);
    assert(NULL != str2);
    
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    int len3 = len1 + len2;
    char *new_str = (char *)malloc(len3 + 1);
    
    // 申請堆空間失敗的情況,是可能的,是允許出現的情況。
    if (!new_str)
        return NULL;
    
    memset(new_str, 0 len3 + 1);
    sprintf(new_str, "%s%s", str1, str2);
    return new_str;
}

對于參數而言:我認為傳入的參數必須是有效的,如果出現了無效參數,說明代碼中存在 bug,不允許出現這樣的情況,必須解決掉。

對于資源分配結果(malloc 函數)而言:我認為資源分配失敗是合理的,是有可能的,是允許出現的,而且我也對這個情況進行了處理。

當然了,并不是說對參數檢查就要使用 assert,主要是根據不同的場景、語義來判斷。例如下面的這個例子:


		
int g_state;
void get_error_str(bool flag)
{
    if (TRUE == flag)
    {
        g_state = 1;
        assert(1 == g_state); // 確保賦值成功
    }
    else
    {
        g_state = 0;
        assert(0 == g_state); // 確保賦值成功
    }
}

flag 參數代表不同的分支情況,而賦值給 g_state 之后,必須保證賦值結果的正確性,因此使用 assert 斷言。

四、總結

這篇文章分析了 C 語言中比較晦澀、模糊的一個概念,似乎有點虛無縹緲,但是的確又需要我們停下來仔細考慮一下。

如果有些場景,實在拿捏不好,我就會問自己一個問題

這種情況是否被允許出現?

不允許:就用 assert 斷言,在開發階段就盡量找出所有的錯誤情況;

允許:就用 if-else,說明這是一個合理的邏輯,需要進行下一步處理。


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5001

    文章

    18394

    瀏覽量

    291040
  • 函數
    +關注

    關注

    3

    文章

    4114

    瀏覽量

    61426
  • 代碼
    +關注

    關注

    30

    文章

    4569

    瀏覽量

    67062

原文標題:嵌入式代碼安全檢查:選擇if還是assert?

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    如何在if和assert中做選擇

    的功能。以前我也是這么想的,但是,現在我不這么認為。 二、assert 斷言剛才,我問了下旁邊的一位工作 5 年多的嵌入式開發者:if 和 assert 如何選擇?他說:
    發表于 04-08 06:13

    嵌入式學習到底選擇自學還是培訓?

    嵌入式自學和參加培訓只是成本問題(時間成本,機會成本、金錢成本),如果你認為自學成本更低,當然可以選擇自學,但往往很多人自學的路并不順暢。于是乎買了了很多數 據結構、C++、操作系統、數 據庫的書
    發表于 06-13 12:02

    FPGA是嵌入式系統設計的理想選擇

    消費電子、物聯網等領域的不斷發展,用戶需求也越來越復雜和多樣,因此我們在嵌入式系統設計中必須選擇合適的處理器(SoC)系統,當然我們也需要考慮成本、功耗、性能、I/O資源等方面,但是隨著實踐案例的增多
    發表于 07-30 18:38

    做IT開發,選擇嵌入式還是JAVA好?

    IT技術領域,選擇多年流行、目前市場基本飽和的JAVA還是目前市場上新興、前沿、國家扶持重視的嵌入式好?下面我們就來了解一下IT技術領域中JAVA開發與嵌入式開發的特點、現狀及未來?!?/div>
    發表于 12-05 11:43

    嵌入式系統編程的語言選擇代碼優化

    ,加上運行環境復雜,使得嵌入式系統軟件的開發變得異常困難。 為了設計一個滿足功能、性能和時間要求的安全可靠的高性能嵌入式系統,編程語言的選擇十分重要。
    發表于 07-22 08:18

    基于Yocto Project的嵌入式應用該怎么設計?

    Linux作為嵌入式系統的主要工具,具有源代碼開放、完全可定制、支持許多網絡協議、服務器級別高、可靠性高等很多優點。但現有的嵌入式Linux市場開始分化,現有的選擇包括半導體廠商提供的
    發表于 08-28 08:18

    嵌入式系統有什么安全技巧?

    中間人攻擊、黑客攻擊、間諜和篡改、內存數據錯誤——嵌入式系統面臨各種威脅。儒卓力GDPR專家團隊主管兼嵌入式和無線部門營銷總監Bertron Hantsche提供了六個安全技巧,以便增強在嵌入
    發表于 10-18 06:28

    如何提升嵌入式系統的VxWorks安全性?

    實時嵌入式系統與網絡的結合以及高可信覆蓋網絡的發展使得嵌入式實時操作系統的安全性問題日益突出。提高實時嵌入式系統的安全性和可靠性是未來實時
    發表于 10-30 06:03

    工作職業是選擇嵌入式還是FPGA?

    也看不上)。如果選擇了FPGA,就只能在有限的幾個公司混了。而且FPGA相對于嵌入式linux更需要懂硬件,甚至有時候要親自動手搞點硬件。但是好處就是門檻高,可替代性差。至于嵌入式linux,崗位多
    發表于 09-22 14:38

    如何選擇嵌入式硬件和芯片?

    如何選擇嵌入式硬件?如何選擇嵌入式芯片?
    發表于 10-25 07:13

    嵌入式 or JAVA該如何去選擇

    **糾結的選擇嵌入式orJAVA**今天已經是失業的第40天了,關于轉型到底是去學習嵌入式還是去學習JAVA,這是一個掉頭發的問題,不知道如何去選擇
    發表于 10-27 06:59

    為什么選擇學習嵌入式?

    什么不懂的可以加群解決:813238832下載鏈接:https://bbs.usoftchina.com/thread-206928-1-1.html圖一為什么選擇學習嵌入式?嵌入式系統無疑是...
    發表于 11-08 06:56

    嵌入式代碼可能存在的致命漏洞是什么

    關注+星標公眾號,不錯過精彩內容來源 |電子伊甸園微信公眾號|嵌入式專欄隨著互聯網的發展,嵌入式設備正分布在一個充滿可以被攻擊者利用的源代碼安全漏洞的環境中。因此,
    發表于 12-17 07:59

    如何調試嵌入式代碼?

    我們在進行嵌入式系統開發調試時,受限于嵌入式芯片資源和性能,一般采用遠程調試。在調試嵌入式底層代碼時,gdbserver 無法運行,我們該怎么調試底層
    發表于 12-17 06:32

    Caché嵌入式代碼分享

    文章目錄第十章 Caché 嵌入式代碼嵌入式HTML`&html`標記語法嵌入式JavaScript嵌入式SQL第十章 Caché
    發表于 12-17 07:19
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>