sprintf(buffer,“%s [...]”,buffer,[...])是否安全?
我看到使用这种模式来连接到在一些代码字符串我工作:sprintf(buffer,“%s [...]”,buffer,[...])是否安全?
sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);
和我相当肯定它不是安全C.你会发现buffer
既是输出和第一个输入。
除了很明显的缓冲区溢出的可能性,我相信不能保证缓冲区不会在函数的开始和结束之间发生变化(即,不能保证什么状态的缓冲区将在执行该功能期间)。 sprintf的签名额外指定目标字符串为restrict
ed。
我还记得一个speculative writing in memcpy的报告,我没有看到为什么一些C库可能在sprintf中做同样的事情。当然,在这种情况下,它将写入其来源。那么这种行为是否安全?
仅供参考,我提议:
char *bufEnd = buffer + strlen(buffer);
/* sprintf returns the number of f'd and print'd into the s */
bufEnd += sprintf(bufEnd, " <input type='file' name='%s' />\r\n", id);
替换此。
从glibc sprintf() documentation:
此函数的行为是 未定义如果进行复制操作,重叠换 例如如果s也作为 参数给定的对象之间的地方 到下控制被打印'%s'转换的 。
它在特定实现中可能是安全的;但你不能指望它是便携式的。
我不确定您的提案在任何情况下都是安全的。你仍然可能是重叠的缓冲区。现在已经很晚了,我的妻子还在纠缠我,但我认为你仍然可能会想要在连接字符串中再次使用原始字符串,并覆盖空字符,因此sprintf实现可能不知道重新使用的位置字符串结束。
您可能只想将snprint()粘贴到临时缓冲区,然后将strncat()粘贴到原始缓冲区上。
好的,只需要一个完整的检查。 [POSIX说同样的事情](http://www.opengroup.org/onlinepubs/9699919799/functions/sprintf.html): >如果复制发生在由于调用sprintf()而重叠的对象之间,或snprintf(),结果是不确定的。 – 2009-08-16 03:00:24
事实上,我在第二个缓冲区中不重叠 - 这是一个严格不同的缓冲区。我不使用原版。 – 2009-08-16 03:14:08
除非你看到我没有的东西,这是完全可能的。 – 2009-08-16 03:15:50
在这个特定的情况下,它将工作,因为buffer
中的字符串将是第一个要输入buffer
(再次无用)的字符串,所以您应该使用strcat()
来代替[几乎相同]影响。
但是,如果你正在尝试strcat()
与sprintf()
的格式化可能性结合起来,你可以试试这个:如果你想连接格式化的文本用printf一个缓冲区的末尾()
sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
,我建议你使用整数来跟踪结束位置。
int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
i += sprintf(&buffer[i], "</td>");
或:
int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
strcat(&buffer[i], "</td>");
而且,人们发狂downvoting这个(“这是不是安全的,您可以缓冲区溢出!”)之前,我只是解决建立一个合理的方式C/C++中的格式化字符串。
我认为你的建议在功能上与我建议的更换相同,但使用的记号略有不同。不过,我可以看出为什么有些人可能更喜欢以这种方式来看待它。 – 2009-08-16 03:47:56
即使它*安全*(不会崩溃等)我可以想象它产生的结果不是预期的结果。 – 2009-08-16 03:08:58
@AndrewMedico那是怎么回事? – cat 2016-09-27 21:49:56