我有以下一段代码,一位同事声称其中可能包含越界读取,我不同意。你能帮忙解决这个争论并解释原因吗?
char *test_filename = malloc(Size + 1);
sprintf(test_filename, "");
if (Size > 0 && Data)
snprintf(test_filename, Size + 1, "%s", Data);
其中 Data
是 const uint8_t *Data
类型的非空终止字符串,Size
是 Data 的大小
,即 Data
中的字节数,类型为 size_t
。
它可能会越界读取,因为格式字符串可能是 %s
?
最佳答案
您的同事是对的。也许不直观, snprintf(test_filename, Size + 1, "%s", Data)
保证读取从 Data
开始的字节,直到遇到 0 字节,在你的情况下通常会导致越界读取。
它只会将这些字节的写入 Size
到test_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/