当我尝试做这样的事情时:
char* prefix = "Sector_Data\\sector";
char* s_num = "0";
std::strcat(prefix, s_num);
std::strcat(prefix, "\\");
依此类推,我收到警告
warning C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead.
为什么strcat被认为是不安全的,有没有办法在不使用strcat_s的情况下摆脱这个警告?
另外,如果摆脱警告的唯一方法是使用strcat_s,它是如何工作的(语法方面:显然它不需要两个参数)。
答案 0 :(得分:29)
如果您使用的是c ++,为什么不避免整个混乱并使用std::string
。没有任何错误的相同示例将如下所示:
std::string prefix = "Sector_Data\\sector";
prefix += "0";
prefix += "\\"
无需担心缓冲区大小和所有这些问题。如果您的API有const char *
,则可以使用.c_str()
成员;
some_c_api(prefix.c_str());
答案 1 :(得分:27)
因为缓冲区前缀的空间可能比复制到它的空间少,导致缓冲区溢出。 因此,黑客可以传入一个特制的字符串,该字符串会覆盖返回地址或其他关键内存,并开始在程序的上下文中执行代码。
strcat_s通过强制你传入要复制字符串的缓冲区的长度来解决这个问题;如果需要,它会截断字符串,以确保缓冲区不会溢出。
google strcat_s以准确了解如何使用它。
答案 2 :(得分:4)
这是C / C ++中的一个字符串操作函数,可能导致缓冲区溢出错误。
问题是该函数不知道缓冲区的大小。从MSDN文档:
第一个参数strDestination, 必须大到足以容纳 当前的strDestination和strSource 合并并关闭'\ 0'; 否则,可能会发生缓冲区溢出。
strcat_s需要一个额外的参数来告诉它缓冲区的大小。这允许它在执行concat之前验证大小,并防止超出。见http://msdn.microsoft.com/en-us/library/d45bbxx4.aspx
答案 3 :(得分:4)
您可以添加以下内容来消除这些警告:
_CRT_SECURE_NO_WARNINGS
和
_SCL_SECURE_NO_WARNINGS
到项目的预处理器定义。
答案 4 :(得分:4)
要关闭警告,您可以执行此操作。
#pragma warning(disable:4996)
不过,我强烈建议您使用strcat_s()。
答案 5 :(得分:3)
因为它无法检查您的案例中的目标字符串(前缀)是否将被写入其边界之外。 strcat本质上是通过循环工作,将源字符串逐字节复制到目标。当它看到一个名为“0”的值(由'\ 0'表示)时,它会停止,称为空终端。由于C没有内置边界检查,并且dest str只是内存中的一个位置,strcat将继续进入ad-infinidium,即使它超过源str或dest。 str没有空终端。
上述解决方案是针对您的Windows环境的特定于平台的。如果你想要平台独立,你必须与strncat争论:
strncat(char* dest, const char* src, size_t count)
智能使用时,这是另一种选择。您可以使用count指定要复制的最大字符数。要做到这一点,你必须弄清楚dest中有多少可用空间(你分配了多少 - strlen(dest))并将其作为计数传递。
答案 6 :(得分:0)
strcat有两个问题。首先,您必须在函数外部进行所有验证,完成与函数几乎相同的工作:
if(pDest+strlen(pDest)+strlen(pScr) < destSize)
你必须沿着两个琴弦的整个长度向下走,以确保它适合,然后沿着它们的整个长度走下去做副本。因此,许多程序员只会假设它适合并跳过测试。更糟糕的是,可能是当代码首次编写时,它是值得保证的,但是当有人添加另一个strcat,或者在程序中的其他地方更改缓冲区大小或常量时,您现在就会遇到问题。
另一个问题是pSrc和pDst是否重叠。根据你的编译器,strcat很可能是简单的循环,它一次在pSrc中检查一个字符为0。如果pDst覆盖了0,那么你将进入一个循环,直到程序崩溃为止。