#C++# 不安全函數(shù)
“ 文章所涉及內(nèi)容更多來自網(wǎng)絡(luò),在此聲明,并感謝知識的貢獻者!”
常見的不安全函數(shù)
—
C++ 常見的不安全函數(shù)
字符串處理函數(shù)
strcpy()
strcpy() 函數(shù)將源字符串復(fù)制到緩沖區(qū)。沒有指定要復(fù)制字符的具體數(shù)目!如果源字符串碰巧來自用戶輸入,且沒有專門限制其大小,則有可能會造成緩沖區(qū)溢出!
解決方法:
確保 strcpy() 不會溢出的另一種方式是,在需要它時就分配空間,確保通過在源字符串上調(diào)用 strlen() 來分配足夠的空間。
dst = (char*)malloc(strlen(src));
strcpy(dst, src);
strcat()
strcat() 函數(shù)非常類似于 strcpy(),除了它可以將一個字符串合并到緩沖區(qū)末尾。
解決方法:
它也有一個類似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。
sprintf()、vsprintf()
函數(shù) sprintf() 和 vsprintf() 是用來格式化文本和將其存入緩沖區(qū)的通用函數(shù)。它們可以用直接的方式模仿 strcpy()
行為。換句話說,使用 sprintf() 和 vsprintf() 與使用 strcpy() 一樣,都很容易對程序造成緩沖區(qū)溢出。
解決方法
sprintf() 的許多版本帶有使用這種函數(shù)的更安全的方法。可以指定格式字符串本身每個自變量的精度。sprintf 采用” * ”來占用一個本來需要一個指定寬度或精度的常數(shù)數(shù)字的位置,而實際的寬度或精度就可以和其它被打印的變量一樣被提供出來。
例如:sprintf(usage,"USAGE: %*s\n", BUF_SIZE, argv[0]);
字符串讀取函數(shù)
gets()
永遠不要使用 gets()。
該函數(shù)從標準輸入讀入用戶輸入的一行文本,它在遇到 EOF 字符或換行字符之前,不會停止讀入文本。也就是:gets() 根本不執(zhí)行邊界檢查。因此,使用 gets() 總是有可能使任何緩沖區(qū)溢出。
解決方法:
作為一個替代方法,可以使用方法 fgets()。它可以做與 gets() 所做的同樣的事情,但它接受用來限制讀入字符數(shù)目的大小參數(shù),因此,提供了一種防止緩沖區(qū)溢出的方法。
getchar()、fgetc()、getc()、read()
如果在循環(huán)中使用這些函數(shù),確保檢查緩沖區(qū)邊界
scanf()系列 : sscanf()、fscanf()、vfscanf()、vscanf()、vsscanf()
scanf系列的函數(shù)也設(shè)計得很差。目的地緩沖區(qū)也可能會發(fā)生溢出。
同樣地,我們用設(shè)置寬度也可以解決這個問題。
getenv()
使用系統(tǒng)調(diào)用 getenv() 的最大問題是您從來不能假定特殊環(huán)境變量是任何特定長度的。
size_type copy(char *buffer, size_type num, size_type index );
因為如果buffer的內(nèi)存大小比num小,那么就會溢出,導(dǎo)致崩潰(而不是異常)。
字符串拷貝的安全API
例如:strcpy, wcscpy等
替代的Safe CRT函數(shù):strcpy_s
有關(guān)字符串合并的API
例如:strcat, wcscat等
替代的Safe CRT函數(shù):strcat_s
有關(guān)sprintf的API
例如:sprintf, swprintf等
替代的Safe CRT函數(shù):
_snprintf_s
_snwprintf_s
gets不能使用,使用gets_s
(gets是老標準C語言函數(shù),vs使用更安全的c11標準, 使用對應(yīng)的gets_s
char line[32];
gets_s(line, sizeof(line));//或者寫為gets_s(line,32);
scanf不能使用
原因同上,改用scanf_s
若用scanf輸入字符串,沒有第三個參數(shù)故不知多長,若長度越界,則占用其他內(nèi)存非常可怕
線程不安全函數(shù)原因解析
— 線程不安全函數(shù)原因淺析
之所線程不安全,是因為這些系統(tǒng)函數(shù)使用了某些全局或者靜態(tài)變量。我們知道,全局變量和靜態(tài)變量分別對應(yīng)內(nèi)存中的全局變量區(qū)和靜態(tài)存儲區(qū),這些區(qū)域都是可以跨函數(shù)跨線程訪問的。一旦在多線程環(huán)境中使用,在沒有加鎖的情況下,對同一段內(nèi)存塊【同個變量】進行并發(fā)讀寫,就會造成segmentfault/coredump之類的問題。
線程不安全函數(shù)類別
— 線程不安全函數(shù)類別
第1類:不保護共享變量的函數(shù)
第2類:函數(shù)中分配,重新分配釋放全局資源
第3類:返回指向靜態(tài)變量的指針的函數(shù),函數(shù)中通過句柄和指針的不直接訪問
第4類:調(diào)用線程不安全函數(shù)的函數(shù)
在編寫線程安全函數(shù)時,要注意兩點:
1、減少對臨界資源的依賴,盡量避免訪問全局變量,靜態(tài)變量或其它共享資源,如果必須要使用共享資源,所有使用到的地方必須要進行互斥鎖 (Mutex) 保護;
2、線程安全的函數(shù)所調(diào)用到的函數(shù)也應(yīng)該是線程安全的,如果所調(diào)用的函數(shù)不是線程安全的,那么這些函數(shù)也必須被互斥鎖 (Mutex) 保護;
線程不安全函數(shù)
— glibc 庫中線程不安全函數(shù)舉例
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
readdir() 函數(shù)為讀取目錄內(nèi)容功能。readdir() 函數(shù)因為內(nèi)部使用了靜態(tài)數(shù)據(jù),即readdir() 函數(shù)調(diào)用成功時,返回指針所指向的 dirent 結(jié)構(gòu)體是靜態(tài)分配的,所以,readdir() 函數(shù)被認為不是線程安全的函數(shù)。
解決方法可以采用局部變量保存數(shù)據(jù),也可以加鎖使用;當(dāng)然還可以使用readdir_r() 函數(shù)。
常見問題
— 解決vs使用c\c++部分函數(shù)提示不安全會直接報錯的問題
https://blog.csdn.net/weixin_44021514/article/details/121801764
參考資料
— 參考資料:
https://blog.csdn.net/weixin_45713725/article/details/109384258
https://blog.csdn.net/ainu412/article/details/105405229
https://baijiahao.baidu.com/s?id=1771285242198274677&wfr=spider&for=pc
https://www.cnblogs.com/mtcnn/p/9421082.html
https://blog.csdn.net/Sky_nnn/article/details/116137344
https://blog.csdn.net/heroisppp/article/details/122833560
https://blog.csdn.net/qq_26499321/article/details/72085592
https://blog.csdn.net/wojiaxiaohuang2014/article/details/128757689
https://vimsky.com/article/3185.html
常見的不安全函數(shù)
—
C++ 常見的不安全函數(shù)
字符串處理函數(shù)
strcpy()
strcpy() 函數(shù)將源字符串復(fù)制到緩沖區(qū)。沒有指定要復(fù)制字符的具體數(shù)目!如果源字符串碰巧來自用戶輸入,且沒有專門限制其大小,則有可能會造成緩沖區(qū)溢出!
解決方法:
確保 strcpy() 不會溢出的另一種方式是,在需要它時就分配空間,確保通過在源字符串上調(diào)用 strlen() 來分配足夠的空間。
dst = (char*)malloc(strlen(src));
strcpy(dst, src);
strcat()
strcat() 函數(shù)非常類似于 strcpy(),除了它可以將一個字符串合并到緩沖區(qū)末尾。
解決方法:
它也有一個類似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。
sprintf()、vsprintf()
函數(shù) sprintf() 和 vsprintf() 是用來格式化文本和將其存入緩沖區(qū)的通用函數(shù)。它們可以用直接的方式模仿 strcpy()
行為。換句話說,使用 sprintf() 和 vsprintf() 與使用 strcpy() 一樣,都很容易對程序造成緩沖區(qū)溢出。
解決方法
sprintf() 的許多版本帶有使用這種函數(shù)的更安全的方法。可以指定格式字符串本身每個自變量的精度。sprintf 采用” * ”來占用一個本來需要一個指定寬度或精度的常數(shù)數(shù)字的位置,而實際的寬度或精度就可以和其它被打印的變量一樣被提供出來。
例如:sprintf(usage,"USAGE: %*s\n", BUF_SIZE, argv[0]);
字符串讀取函數(shù)
gets()
永遠不要使用 gets()。
該函數(shù)從標準輸入讀入用戶輸入的一行文本,它在遇到 EOF 字符或換行字符之前,不會停止讀入文本。也就是:gets() 根本不執(zhí)行邊界檢查。因此,使用 gets() 總是有可能使任何緩沖區(qū)溢出。
解決方法:
作為一個替代方法,可以使用方法 fgets()。它可以做與 gets() 所做的同樣的事情,但它接受用來限制讀入字符數(shù)目的大小參數(shù),因此,提供了一種防止緩沖區(qū)溢出的方法。
getchar()、fgetc()、getc()、read()
如果在循環(huán)中使用這些函數(shù),確保檢查緩沖區(qū)邊界
scanf()系列 : sscanf()、fscanf()、vfscanf()、vscanf()、vsscanf()
scanf系列的函數(shù)也設(shè)計得很差。目的地緩沖區(qū)也可能會發(fā)生溢出。
同樣地,我們用設(shè)置寬度也可以解決這個問題。
getenv()
使用系統(tǒng)調(diào)用 getenv() 的最大問題是您從來不能假定特殊環(huán)境變量是任何特定長度的。
size_type copy(char *buffer, size_type num, size_type index );
因為如果buffer的內(nèi)存大小比num小,那么就會溢出,導(dǎo)致崩潰(而不是異常)。
字符串拷貝的安全API
—
有關(guān)字符串拷貝的API例如:strcpy, wcscpy等
替代的Safe CRT函數(shù):strcpy_s
有關(guān)字符串合并的API
例如:strcat, wcscat等
替代的Safe CRT函數(shù):strcat_s
有關(guān)sprintf的API
例如:sprintf, swprintf等
替代的Safe CRT函數(shù):
_snprintf_s
_snwprintf_s
gets不能使用,使用gets_s
(gets是老標準C語言函數(shù),vs使用更安全的c11標準, 使用對應(yīng)的gets_s
char line[32];
gets_s(line, sizeof(line));//或者寫為gets_s(line,32);
scanf不能使用
原因同上,改用scanf_s
若用scanf輸入字符串,沒有第三個參數(shù)故不知多長,若長度越界,則占用其他內(nèi)存非常可怕
線程不安全函數(shù)原因解析
— 線程不安全函數(shù)原因淺析
之所線程不安全,是因為這些系統(tǒng)函數(shù)使用了某些全局或者靜態(tài)變量。我們知道,全局變量和靜態(tài)變量分別對應(yīng)內(nèi)存中的全局變量區(qū)和靜態(tài)存儲區(qū),這些區(qū)域都是可以跨函數(shù)跨線程訪問的。一旦在多線程環(huán)境中使用,在沒有加鎖的情況下,對同一段內(nèi)存塊【同個變量】進行并發(fā)讀寫,就會造成segmentfault/coredump之類的問題。
線程不安全函數(shù)類別
— 線程不安全函數(shù)類別
第1類:不保護共享變量的函數(shù)
第2類:函數(shù)中分配,重新分配釋放全局資源
第3類:返回指向靜態(tài)變量的指針的函數(shù),函數(shù)中通過句柄和指針的不直接訪問
第4類:調(diào)用線程不安全函數(shù)的函數(shù)
在編寫線程安全函數(shù)時,要注意兩點:
1、減少對臨界資源的依賴,盡量避免訪問全局變量,靜態(tài)變量或其它共享資源,如果必須要使用共享資源,所有使用到的地方必須要進行互斥鎖 (Mutex) 保護;
2、線程安全的函數(shù)所調(diào)用到的函數(shù)也應(yīng)該是線程安全的,如果所調(diào)用的函數(shù)不是線程安全的,那么這些函數(shù)也必須被互斥鎖 (Mutex) 保護;
線程不安全函數(shù)
— glibc 庫中線程不安全函數(shù)舉例
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
readdir() 函數(shù)為讀取目錄內(nèi)容功能。readdir() 函數(shù)因為內(nèi)部使用了靜態(tài)數(shù)據(jù),即readdir() 函數(shù)調(diào)用成功時,返回指針所指向的 dirent 結(jié)構(gòu)體是靜態(tài)分配的,所以,readdir() 函數(shù)被認為不是線程安全的函數(shù)。
解決方法可以采用局部變量保存數(shù)據(jù),也可以加鎖使用;當(dāng)然還可以使用readdir_r() 函數(shù)。
常見問題
— 解決vs使用c\c++部分函數(shù)提示不安全會直接報錯的問題
https://blog.csdn.net/weixin_44021514/article/details/121801764
參考資料
— 參考資料:
https://blog.csdn.net/weixin_45713725/article/details/109384258
https://blog.csdn.net/ainu412/article/details/105405229
https://baijiahao.baidu.com/s?id=1771285242198274677&wfr=spider&for=pc
https://www.cnblogs.com/mtcnn/p/9421082.html
https://blog.csdn.net/Sky_nnn/article/details/116137344
https://blog.csdn.net/heroisppp/article/details/122833560
https://blog.csdn.net/qq_26499321/article/details/72085592
https://blog.csdn.net/wojiaxiaohuang2014/article/details/128757689
https://vimsky.com/article/3185.html
評論
圖片
表情
