C中的"坏"功能是什么,它们的"好"选择是什么?
为什么坏的不好,是什么让好的更好?
我知道,例如,它gets()
是"坏的",因为它没有任何形式的边界检查.什么是更好的选择?gets()
?
我听说gets()
很糟糕,但我不记得为什么.谁知道?什么是最好的选择?
还有更多吗?
Ada*_*kin 46
在过去,大多数字符串函数都没有边界检查.当然,他们不能只删除旧函数,或修改其签名以包含上限,这会破坏兼容性.现在,对于几乎所有这些功能,都有一个替代的"n"版本.例如:
strcpy -> strncpy
strlen -> strnlen
strcmp -> strncmp
strcat -> strncat
strdup -> strndup
sprintf -> snprintf
wcscpy -> wcsncpy
wcslen -> wcsnlen
Run Code Online (Sandbox Code Playgroud)
和更多.
编辑2013-12-03:
另请参阅https://github.com/leafsr/gcc-poison,这是一个创建头文件的项目,如果您使用不安全的函数,该文件会导致gcc报告错误.
caf*_*caf 34
是的,fgets(,, STDIN)是gets()的一个很好的替代品,因为它需要一个size参数.
scanf()在某些情况下被认为是有问题的,而不是直接"坏",因为如果输入不符合预期的格式,则无法合理地恢复(它不会让你回放输入并尝试再次).如果你可以放弃格式错误的输入,它是可用的.这里的"更好"替代方法是使用输入函数(如fgets()或fgetc())来读取输入块,然后使用sscanf()扫描它或使用strchr()和strtol()等字符串处理函数对其进行解析.另请参阅下面的scanf()中"%s"转换说明符的特定问题.
它不是标准的C函数,但BSD和POSIX函数mktemp()通常不可能安全使用,因为在测试文件存在和创建文件之间始终存在竞争条件.mkstemp()或tmpfile()是很好的替代品.
strncpy()是一个稍微棘手的函数,因为如果没有空间,它不会终止目标.您可以通过自己将nul-terminator添加到目标,或者将目标设置为空字符串然后使用strncat()来解决此问题.
在某些情况下,atoi()可能是一个糟糕的选择,因为你无法判断转换时是否有错误(例如,如果数字超出了int的范围).如果这对您很重要,请使用strtol().
strcpy(),strcat()和sprintf()遇到类似于gets()的问题 - 它们不允许您指定目标缓冲区的大小.它仍然是可能的,至少在理论上,安全地使用它们-但你多过使用strncat函数()和snprintf的(),而不是更好的(你可以使用函数strncpy(),但是见上文).在同一主题上,如果您使用scanf()系列函数,请不要使用普通的"%s" - 指定目标的大小,例如."%200S".
Dav*_*kle 20
strtok()通常被认为是邪恶的,因为它在调用之间存储状态信息.不要尝试在多线程环境中运行THAT!
Sec*_*ure 11
严格来说,有一个非常危险的功能.它是gets()因为它的输入不受程序员的控制.这里提到的所有其他功能本身都是安全的."好"和"坏"归结为防御性编程,即前置条件,后置条件和样板代码.
我们以strcpy()为例.它有一些程序员在调用函数之前必须满足的前提条件.两个字符串必须是有效的,非NULL指针,以零终止字符串,并且目标必须提供足够的空间,最终字符串长度在size_t范围内.另外,两个字符串都不允许重叠.
这是很多前提条件,strcpy()都没有检查它们.程序员必须确保它们已经完成,或者在调用strcpy()之前必须用额外的样板代码明确地测试它们:
n = DST_BUFFER_SIZE;
if ((dst != NULL) && (src != NULL) && (strlen(dst)+strlen(src)+1 <= n))
{
strcpy(dst, src);
}
Run Code Online (Sandbox Code Playgroud)
已经默默地假设非重叠和零终止字符串.
strncpy()确实包含了一些这些检查,但它增加了程序员在调用函数后必须注意的另一个后置条件,因为结果可能不是零终止的.
strncpy(dst, src, n);
if (n > 0)
{
dst[n-1] = '\0';
}
Run Code Online (Sandbox Code Playgroud)
为什么这些功能被认为是"坏"?因为当程序员假定有效性错误时,他们需要为每次调用提供额外的样板代码以确保安全,程序员往往会忘记这段代码.
甚至反对它.以printf()系列为例.这些函数返回指示错误和成功的状态.谁检查输出到stdout或stderr是否成功?认为当标准通道不起作用时你根本无法做任何事情.那么,如何使用错误指示退出代码来挽救用户数据并终止程序呢?而不是可能的崩溃和烧毁替代与损坏的用户数据.
在时间和资金有限的环境中,始终存在的问题是您真正想要多少安全网以及最终的最坏情况?如果是str函数的缓冲区溢出,那么禁止它们是有意义的,并且可能提供已经在其中的安全网的包装函数.
关于这一点的最后一个问题:是什么让你确定你的"好"替代方案真的很好?
归档时间: |
|
查看次数: |
26127 次 |
最近记录: |