官术网_书友最值得收藏!

建議2-3:使用rsize_t或size_t類型來表示一個對象所占用空間的整數值單位

C語言標準規定size_t是一種無符號整數類型,編譯器可以根據操作系統的不同而用typedef來定義不同的size_t類型,即在不同的操作系統上所定義的size_t可能不一樣。例如在32位操作系統上可以將size_t定義為unsigned int類型,而在64位操作系統上則可以定義為unsigned long int類型,甚至還可以將size_t定義為unsigned long long int類型等,如下面的示例所示。

在GCC的stddef.h文件中將size_t定義為:


#ifndef __SIZE_TYPE__
#define __SIZE_TYPE__ long unsigned int
#endif
#if !(defined (__GNUG__) && defined (size_t))
typedef __SIZE_TYPE__ size_t;
#ifdef __BEOS__
typedef long ssize_t;
#endif /* __BEOS__ */

而在VC++2010的crtdefs.h文件中將size_t定義為:


#ifndef _SIZE_T_DEFINED
#ifdef  _WIN64
typedef unsigned __int64    size_t;
#else
typedef _W64 unsigned int   size_t;
#endif
#define _SIZE_T_DEFINED
#endif

從上面的定義可以看出,size_t類型的引入增強了程序在不同平臺上的可移植性,而它也正是為了方便系統之間的移植而定義的。size_t類型的變量大小足以保證存儲內存中對象的大小,任何表示對象長度的變量,包括作為大小、索引、循環計數和長度的整數值,都可以聲明為size_t類型。比如我們常用的sizeof操作符的結果返回的就是size_t類型,該類型保證能容納實現所建立的最大對象的字節大小。size_t類型的限制是由SIZE_MAX宏指定的。

接下來看看size_t類型的使用示例,如代碼清單1-3所示。

代碼清單1-3 size_t類型的使用示例


char *copy(size_t n, const char *str)
{
    int i;
    char *p;
    if (n == 0)
    {
            /* 處理n==0的情況 */
    }
    p = (char *)malloc(n);
    if (p == NULL)
    {
            /*處理p==NULL的情況 */
    }
    for ( i = 0; i < n; ++i )
    {
            p[i] = *str++;
    }
    return p;
}

不難發現,代碼清單1-3中存在著一個嚴重的問題:當p所引用的動態分配的緩沖區在n>INT_MAX時將會發生溢出。我們知道,int類型的限制是由INT_MAX宏指定的,而size_t類型代表的是一個無符號整數類型,它可能包含一個大于INT_MAX的值。因此,當n的值為0<n<=INT_MAX時,執行循環n次,代碼如預期一樣正常運行;但當n的值為INT_MAX<n<=SIZE_MAX,且整型變量i的增值超過INT_MAX時,i的值將是從INT_MIN開始的負值。這時,p[i]所引用的內存位置是在p所引用的內存之前,這就會導致寫入發生在數組邊界之外。

因此,為了避免發生這種潛在性的錯誤,應該將變量i也聲明成size_t類型,如代碼清單1-4所示。

代碼清單1-4 代碼清單1-3的解決方法


char *copy(size_t n, const char *str)
{
    size_t i;
    char *p;
    if (n == 0||n>SIZE_MAX)
    {
            /* 處理n==0的情況 */
    }
    p = (char *)malloc(n);
    if (p == NULL)
    {
            /*處理p==NULL的情況 */
    }
    for ( i = 0; i < n; ++i )
    {
        p[i] = *str++;
    }
    return p;
}

除了size_t類型之外,ISO/IEC TR 24731-1:2007中引入了一種新類型rsize_t,雖然它被定義為size_t類型,但它明確地表示是用于保存單個對象的長度的。

在VC++2010的crtdefs.h文件中將rsize_t定義為:


#if __STDC_WANT_SECURE_LIB__
#ifndef _RSIZE_T_DEFINED
typedef size_t rsize_t;
#define _RSIZE_T_DEFINED
#endif
#endif

在支持rsize_t類型的代碼中,你可以檢查對象的長度,驗證它不大于RSIZE_MAX(一個正常單個對象的最大長度),庫函數也可以使用rsize_t進行輸入校驗。

在VC++2010的limits.h文件中將RSIZE_MAX定義為:


#if __STDC_WANT_SECURE_LIB__
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif
#endif

這樣就消除了示例整數溢出的可能性,現在我們可以將代碼清單1-3中的變量i聲明成rsize_t類型,同時也可將參數n修改成rsize_t類型,并與RSIZE_MAX進行比較以驗證數據的合法范圍,如代碼清單1-5所示。

代碼清單1-5 代碼清單1-3的rsize_t解決方法


char *copy(rsize_t n, const char *str)
{
    rsize_t i;
    char *p;
    if (n == 0 || n > RSIZE_MAX)
    {
            /* 處理n==0|| n > RSIZE_MAX的情況 */
    }
    p = (char *)malloc(n);
    if (p == NULL)
    {
            /*處理p==NULL的情況 */
    }
    for (i = 0; i < n; ++i)
    {
            p[i] = *str++;
    }
    return p;
}

主站蜘蛛池模板: 米泉市| 浦城县| 连云港市| 广宗县| 湖口县| 镇康县| 台东县| 张家港市| 孝义市| 建德市| 沙河市| 通辽市| 平谷区| 丰宁| 郎溪县| 广水市| 灵川县| 天等县| 平昌县| 丹巴县| 周口市| 上高县| 台州市| 托克托县| 拜泉县| 洪泽县| 吉木萨尔县| 建昌县| 关岭| 杭州市| 勐海县| 休宁县| 香港| 武邑县| 达孜县| 连山| 忻州市| 天等县| 班玛县| 郓城县| 九寨沟县|