sprintf(buffer, "%s […]", buffer, […]) 安全吗?

发布于 2024-08-01 18:53:24 字数 817 浏览 5 评论 0 原文

我在我正在处理的一些代码中看到使用此模式连接到字符串:

sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);

并且我相当确定它不安全 C。您会注意到 buffer 既是输出又是第一个输入。

除了明显的缓冲区溢出可能性之外,我相信不能保证缓冲区在函数的开始和结束之间不会发生变化(即,不能保证函数的内容)缓冲区的状态将在函数执行期间)。 sprintf 的签名还指定目标字符串是受限制的。

我还记得一份关于在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);

替换它。

I saw use of this pattern to concatenate onto a string in some code I was working on:

sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);

and I'm fairly certain it's not safe C. You'll notice that buffer is both the output and the first input.

Apart from the obvious possibility of a buffer overflow, I believe there is no guarantee that buffer doesn't get changed between the start and the end of the function (i.e., there is no guarantee as to what the state of buffer will be during the execution of the function). The signature of sprintf additionally specifies that the target string is restricted.

I also recall a report of a speculative writing in memcpy, and I see no reason why some C library might do the same thing in a sprintf. In this case, of course, it would be writing to its source. So is this behaviour safe?

FYI, I proposed:

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);

to replace this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

逐鹿 2024-08-08 18:53:24

来自 glibc sprintf() 文档 :

该函数的行为是
如果发生复制则未定义
重叠的物体之间——对于
例如,如果 s 也作为
在控制下打印的参数
'%s' 转换。

在特定的实现中它可能是安全的; 但你不能指望它是便携式的。

我也不确定您的建议在所有情况下都是安全的。 您仍然可能会重叠缓冲区。 已经很晚了,我的妻子正在烦我,但我认为您仍然可能会遇到这样的情况:您想在连接字符串中再次使用原始字符串并覆盖空字符,因此 sprintf 实现可能不知道在哪里重新使用字符串结束。

您可能只想将 snprint() 保留到临时缓冲区,然后将 strncat() 保留到原始缓冲区。

From the glibc sprintf() documentation:

The behavior of this function is
undefined if copying takes place
between objects that overlap—for
example, if s is also given as an
argument to be printed under control
of the ‘%s’ conversion.

It may be safe in a particular implementation; but you could not count on it being portable.

I'm not sure that your proposal would be safe in all cases either. You could still be overlapping buffers. It's late and my wife is buggin me but I think that you could still have the case where you want to use the original string again in the concatenated string and are overwriting the null character and so the sprintf implementation might not know where the re-used string ends.

You might just want to stick with a snprint() to a temp buffer, then strncat() it onto the original buffer.

娇纵 2024-08-08 18:53:24

如果您想使用 printf() 将格式化文本连接到缓冲区的末尾,我建议您使用整数来跟踪结束位置。

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>");

在人们对此疯狂反对之前(“这不安全!你可能会超出缓冲区!”),我只是提出一种在 C/C++ 中构建格式化字符串的合理方法。

If you want to concatenate formatted text to the end of a buffer using printf(), I'd recommend you use an integer to keep track of the end position.

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
i += sprintf(&buffer[i], "</td>");

or:

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
strcat(&buffer[i], "</td>");

And before people go berserk downvoting this ("This isn't safe! You can overrun the buffer!"), I'm just addressing a reasonable way to build a formatted string in C/C++.

久随 2024-08-08 18:53:24

在这种特定情况下,它会起作用,因为 buffer 中的字符串将是第一个进入 buffer 的内容(同样,无用),所以你应该使用 strcat() 来获得[几乎]相同的效果。

但是,如果您尝试将 strcat()sprintf() 的格式化功能结合起来,您可以尝试以下操作:

sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);

In this specific case, it is going to work because the string in buffer will be the first thing that is going to enter in buffer (again, useless), so you should use strcat() instead to get the [almost] same effect.

But, if you are trying to combine strcat() with the formating possibilities of sprintf(), you may try this:

sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文