我有以下一段代码,一位同事声称其中可能包含越界读取,我不同意。你能帮助解决这个争论并解释原因吗?
char *test_filename = malloc(Size + 1);
sprintf(test_filename, "");
if (Size > 0 && Data)
snprintf(test_filename, Size + 1, "%s", Data);
Run Code Online (Sandbox Code Playgroud)
其中Data是式的非空终止字符串const uint8_t *Data和Size是的大小Data,即,以字节为单位的数目Data,类型的size_t。
它可能读取越界,因为格式字符串%s可能是 ?
你的同事是对的。也许不直观,snprintf(test_filename, Size + 1, "%s", Data)保证从Data0 字节开始读取字节,在您的情况下,通常会导致越界读取。
它只会将这些字节写入 并空终止它们,尊重目标的大小限制;但它会继续阅读。这样做的原因是一种设计选择,它使调用者能够在实际写入任何内容之前确定动态分配所需的目标大小:返回如果目标具有无限空间将写入的字节数。此功能应该与目标大小为 0 一起使用(并且可能使用空指针作为目标)。此功能对于不是字符串的参数很有用:对于数字等,输出的大小很难预测(例如,取决于语言环境),最好在运行时留给函数。Sizetest_filenamesnprintf()
同时返回值指示输出是否被截断:如果大于或等于 size 参数,则并非所有输入都在输出中使用。在您的情况下,遗漏的是从 a 开始Data[Size]并以第一个 0 字节结束的字节,或者分段错误 ;-)。
修复建议:首先不清楚为什么要使用printf家庭来打印字符串;简单地复制它。然后安德鲁在他的评论中有一点,因为Data不是空终止,所以它不是真正的字符串(即使所有字节都是可打印的);所以不要开始摆弄strcpy和朋友,而只是简单memcpy()的字节和 null 手动终止。
哦,前面sprintf(test_filename, "");没有任何明显的目的。如果您想将空字节写入*Data,只需这样做;但是由于您没有使用strcat,这将依赖于终止的目标字符串来扩展,因此非常没有必要。