C语言 一些不安全的库函数
那些不安全的库函数
C 和 C++ 不能够自动地做边界检查,边界检查的代价是效率。一般来讲,C 在大多数情况下注重效率。然而,获得效率的代价是,C 程序员必须十分警觉以避免缓冲区溢出问题。
C语言标准库中的许多字符串处理和IO流读取函数是导致缓冲区溢出的罪魁祸首。我们有必要了解这些函数,在编程中多加小心。
一、字符串处理函数
strcpy()
strcpy() 函数将源字符串复制到缓冲区。没有指定要复制字符的具体数目!如果源字符串碰巧来自用户输入,且没有专门限制其大小,则有可能会造成缓冲区溢出!
我们也可以使用strncpy来完成同样的目的:
strncpy (dst, src, dst_size-1);
如果 src 比 dst 大,则该函数不会抛出一个错误;当达到最大尺寸时,它只是停止复制字符。注意上面调用 strncpy() 中的 -1。如果 src 比 dst 长,则那给我们留有空间,将一个空字符放在 dst 数组的末尾。
但是! strncpy()也不完全安全,也有可能把事情搞糟。即使“安全”的调用有时会留下未终止的字符串,或者会发生微妙的相差一位错误。
确保 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() 的最大问题是您从来不能假定特殊环境变量是任何特定长度的。
三、使用安全版本的代码库
微软对于有缓冲溢出危险的API使用其开发的安全版本的库来替代。 SafeCRT自Visual Studio 2005起开始支持。当代码中使用了禁用的危险的CRT函数,Visual Studio 2005编译时会报告相应警告信息,以提醒开发人员考虑将其替代为Safe CRT中更为安全。
-
有关字符串拷贝的API
例如:strcpy, wcscpy等
替代的Safe CRT函数:strcpy_s
-
有关字符串合并的API
例如:strcat, wcscat等
替代的Safe CRT函数:strcat_s
-
有关sprintf的API
例如:sprintf, swprintf等
替代的Safe CRT函数:
_snprintf_s
_snwprintf_s
其它被禁用的API还有scanf, strtok, gets, itoa等等。 ”n”系列的字符串处理函数,例如strncpy等,也在被禁用之列。
更多建议: