#C++# 不安全函数
“ 文章所涉及内容更多来自网络,在此声明,并感谢知识的贡献者!”
常见的不安全函数
—
C++ 常见的不安全函数
字符串处理函数
strcpy()
strcpy() 函数将源字符串复制到缓冲区。没有指定要复制字符的具体数目!如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会造成缓冲区溢出!
解决方法:
确保 strcpy() 不会溢出的另一种方式是,在需要它时就分配空间,确保通过在源字符串上调用 strlen() 来分配足够的空间。
dst = (char*)malloc(strlen(src));
strcpy(dst, src);
strcat()
strcat() 函数非常类似于 strcpy(),除了它可以将一个字符串合并到缓冲区末尾。
解决方法:
它也有一个类似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。
sprintf()、vsprintf()
函数 sprintf() 和 vsprintf() 是用来格式化文本和将其存入缓冲区的通用函数。它们可以用直接的方式模仿 strcpy()
行为。换句话说,使用 sprintf() 和 vsprintf() 与使用 strcpy() 一样,都很容易对程序造成缓冲区溢出。
解决方法
sprintf() 的许多版本带有使用这种函数的更安全的方法。可以指定格式字符串本身每个自变量的精度。sprintf 采用” * ”来占用一个本来需要一个指定宽度或精度的常数数字的位置,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来。
例如:sprintf(usage,"USAGE: %*s\n", BUF_SIZE, argv[0]);
字符串读取函数
gets()
永远不要使用 gets()。
该函数从标准输入读入用户输入的一行文本,它在遇到 EOF 字符或换行字符之前,不会停止读入文本。也就是:gets() 根本不执行边界检查。因此,使用 gets() 总是有可能使任何缓冲区溢出。
解决方法:
作为一个替代方法,可以使用方法 fgets()。它可以做与 gets() 所做的同样的事情,但它接受用来限制读入字符数目的大小参数,因此,提供了一种防止缓冲区溢出的方法。
getchar()、fgetc()、getc()、read()
如果在循环中使用这些函数,确保检查缓冲区边界
scanf()系列 : sscanf()、fscanf()、vfscanf()、vscanf()、vsscanf()
scanf系列的函数也设计得很差。目的地缓冲区也可能会发生溢出。
同样地,我们用设置宽度也可以解决这个问题。
getenv()
使用系统调用 getenv() 的最大问题是您从来不能假定特殊环境变量是任何特定长度的。
size_type copy(char *buffer, size_type num, size_type index );
因为如果buffer的内存大小比num小,那么就会溢出,导致崩溃(而不是异常)。
字符串拷贝的安全API
例如:strcpy, wcscpy等
替代的Safe CRT函数:strcpy_s
有关字符串合并的API
例如:strcat, wcscat等
替代的Safe CRT函数:strcat_s
有关sprintf的API
例如:sprintf, swprintf等
替代的Safe CRT函数:
_snprintf_s
_snwprintf_s
gets不能使用,使用gets_s
(gets是老标准C语言函数,vs使用更安全的c11标准, 使用对应的gets_s
char line[32];
gets_s(line, sizeof(line));//或者写为gets_s(line,32);
scanf不能使用
原因同上,改用scanf_s
若用scanf输入字符串,没有第三个参数故不知多长,若长度越界,则占用其他内存非常可怕
线程不安全函数原因解析
— 线程不安全函数原因浅析
之所线程不安全,是因为这些系统函数使用了某些全局或者静态变量。我们知道,全局变量和静态变量分别对应内存中的全局变量区和静态存储区,这些区域都是可以跨函数跨线程访问的。一旦在多线程环境中使用,在没有加锁的情况下,对同一段内存块【同个变量】进行并发读写,就会造成segmentfault/coredump之类的问题。
线程不安全函数类别
— 线程不安全函数类别
第1类:不保护共享变量的函数
第2类:函数中分配,重新分配释放全局资源
第3类:返回指向静态变量的指针的函数,函数中通过句柄和指针的不直接访问
第4类:调用线程不安全函数的函数
在编写线程安全函数时,要注意两点:
1、减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其它共享资源,如果必须要使用共享资源,所有使用到的地方必须要进行互斥锁 (Mutex) 保护;
2、线程安全的函数所调用到的函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁 (Mutex) 保护;
线程不安全函数
— glibc 库中线程不安全函数举例
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
readdir() 函数为读取目录内容功能。readdir() 函数因为内部使用了静态数据,即readdir() 函数调用成功时,返回指针所指向的 dirent 结构体是静态分配的,所以,readdir() 函数被认为不是线程安全的函数。
解决方法可以采用局部变量保存数据,也可以加锁使用;当然还可以使用readdir_r() 函数。
常见问题
— 解决vs使用c\c++部分函数提示不安全会直接报错的问题
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
常见的不安全函数
—
C++ 常见的不安全函数
字符串处理函数
strcpy()
strcpy() 函数将源字符串复制到缓冲区。没有指定要复制字符的具体数目!如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会造成缓冲区溢出!
解决方法:
确保 strcpy() 不会溢出的另一种方式是,在需要它时就分配空间,确保通过在源字符串上调用 strlen() 来分配足够的空间。
dst = (char*)malloc(strlen(src));
strcpy(dst, src);
strcat()
strcat() 函数非常类似于 strcpy(),除了它可以将一个字符串合并到缓冲区末尾。
解决方法:
它也有一个类似的、更安全的替代方法 strncat()。如果可能,使用 strncat() 而不要使用 strcat()。
sprintf()、vsprintf()
函数 sprintf() 和 vsprintf() 是用来格式化文本和将其存入缓冲区的通用函数。它们可以用直接的方式模仿 strcpy()
行为。换句话说,使用 sprintf() 和 vsprintf() 与使用 strcpy() 一样,都很容易对程序造成缓冲区溢出。
解决方法
sprintf() 的许多版本带有使用这种函数的更安全的方法。可以指定格式字符串本身每个自变量的精度。sprintf 采用” * ”来占用一个本来需要一个指定宽度或精度的常数数字的位置,而实际的宽度或精度就可以和其它被打印的变量一样被提供出来。
例如:sprintf(usage,"USAGE: %*s\n", BUF_SIZE, argv[0]);
字符串读取函数
gets()
永远不要使用 gets()。
该函数从标准输入读入用户输入的一行文本,它在遇到 EOF 字符或换行字符之前,不会停止读入文本。也就是:gets() 根本不执行边界检查。因此,使用 gets() 总是有可能使任何缓冲区溢出。
解决方法:
作为一个替代方法,可以使用方法 fgets()。它可以做与 gets() 所做的同样的事情,但它接受用来限制读入字符数目的大小参数,因此,提供了一种防止缓冲区溢出的方法。
getchar()、fgetc()、getc()、read()
如果在循环中使用这些函数,确保检查缓冲区边界
scanf()系列 : sscanf()、fscanf()、vfscanf()、vscanf()、vsscanf()
scanf系列的函数也设计得很差。目的地缓冲区也可能会发生溢出。
同样地,我们用设置宽度也可以解决这个问题。
getenv()
使用系统调用 getenv() 的最大问题是您从来不能假定特殊环境变量是任何特定长度的。
size_type copy(char *buffer, size_type num, size_type index );
因为如果buffer的内存大小比num小,那么就会溢出,导致崩溃(而不是异常)。
字符串拷贝的安全API
—
有关字符串拷贝的API例如:strcpy, wcscpy等
替代的Safe CRT函数:strcpy_s
有关字符串合并的API
例如:strcat, wcscat等
替代的Safe CRT函数:strcat_s
有关sprintf的API
例如:sprintf, swprintf等
替代的Safe CRT函数:
_snprintf_s
_snwprintf_s
gets不能使用,使用gets_s
(gets是老标准C语言函数,vs使用更安全的c11标准, 使用对应的gets_s
char line[32];
gets_s(line, sizeof(line));//或者写为gets_s(line,32);
scanf不能使用
原因同上,改用scanf_s
若用scanf输入字符串,没有第三个参数故不知多长,若长度越界,则占用其他内存非常可怕
线程不安全函数原因解析
— 线程不安全函数原因浅析
之所线程不安全,是因为这些系统函数使用了某些全局或者静态变量。我们知道,全局变量和静态变量分别对应内存中的全局变量区和静态存储区,这些区域都是可以跨函数跨线程访问的。一旦在多线程环境中使用,在没有加锁的情况下,对同一段内存块【同个变量】进行并发读写,就会造成segmentfault/coredump之类的问题。
线程不安全函数类别
— 线程不安全函数类别
第1类:不保护共享变量的函数
第2类:函数中分配,重新分配释放全局资源
第3类:返回指向静态变量的指针的函数,函数中通过句柄和指针的不直接访问
第4类:调用线程不安全函数的函数
在编写线程安全函数时,要注意两点:
1、减少对临界资源的依赖,尽量避免访问全局变量,静态变量或其它共享资源,如果必须要使用共享资源,所有使用到的地方必须要进行互斥锁 (Mutex) 保护;
2、线程安全的函数所调用到的函数也应该是线程安全的,如果所调用的函数不是线程安全的,那么这些函数也必须被互斥锁 (Mutex) 保护;
线程不安全函数
— glibc 库中线程不安全函数举例
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
readdir() 函数为读取目录内容功能。readdir() 函数因为内部使用了静态数据,即readdir() 函数调用成功时,返回指针所指向的 dirent 结构体是静态分配的,所以,readdir() 函数被认为不是线程安全的函数。
解决方法可以采用局部变量保存数据,也可以加锁使用;当然还可以使用readdir_r() 函数。
常见问题
— 解决vs使用c\c++部分函数提示不安全会直接报错的问题
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
评论