当字符串参数不是以 null 结尾时, `snprintf()` 是否可以越界读取?

标签 c string printf

我有以下一段代码,一位同事声称其中可能包含越界读取,我不同意。你能帮忙解决这个争论并解释原因吗?

char *test_filename = malloc(Size + 1);
sprintf(test_filename, "");

if (Size > 0 && Data)
  snprintf(test_filename, Size + 1, "%s", Data);

其中 Dataconst uint8_t *Data 类型的非空终止字符串,SizeData 的大小,即 Data 中的字节数,类型为 size_t

它可能会越界读取,因为格式字符串可能是 %s

最佳答案

您的同事是对的。也许不直观, snprintf(test_filename, Size + 1, "%s", Data) 保证读取从 Data 开始的字节,直到遇到 0 字节,在你的情况下通常会导致越界读取。

它只会将这些字节的写入 Sizetest_filename 并以null 终止它们,尊重目标的大小限制;但它将继续阅读。这样做的原因是一种设计选择,它使调用者能够在实际写入任何内容之前确定动态分配所需的目标大小:snprintf() 返回字节数< em>如果目标有无限空间,将被写入。此功能应该用于目标大小为 0(并且可能是空指针作为目标)。此功能对于不是字符串的参数很有用:对于数字等,输出的大小很难预测(例如,取决于语言环境),最好在运行时留给函数​​。

同时返回值表示输出是否被截断:如果大于或等于大小参数,则不是所有的输入都被用于输出。在您的情况下,遗漏的是从 Data[Size] 开始并以第一个 0 字节结束的字节,或者是段错误 ;-)。

修复建议:首先不清楚为什么要使用 printf 系列来打印字符串;只需复制它。然后 Andrew 在他的评论中有一个观点,因为 Data 不是空终止的,所以它不是真正的字符串(即使所有字节都是可打印的);所以不要开始摆弄 strcpy 和 friend ,而是简单地 memcpy() 字节,然后手动终止 null。

哦,前面的 sprintf(test_filename, ""); 没有任何明显的目的。如果您想向*Data 写入一个空字节,只需这样做;但是由于您没有使用 strcat,它会依赖于终止的目标字符串来扩展,所以这是完全没有必要的。

关于当字符串参数不是以 null 结尾时, `snprintf()` 是否可以越界读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63151686/

相关文章:

使用 printf 时,C fork 是父级的副本

c - 如果仅尾随 0,则使用 printf 格式化没有小数位的 float

javascript - 将整数转换为字节串

c - 以下代码的时间复杂度

c - 垃圾值(value)不知道从哪里来

c - 并非for循环中的所有指令都被执行

python - 如何在 python 中左对齐字符串的一部分?

c++ - getline() 分隔符问题

c - snprintf - 格式化不是字符串文字并且没有格式参数警告

c - 为什么在 C 中创建指向 const 的指针的指针是非法的?