我正在编写需要格式化字符串的代码,并且希望避免缓冲区溢出。
我知道,如果vsnprintf可用(C99以后),我们可以:
char* formatString(const char *format, ...)
{
char* result = NULL;
va_list ap;
va_start(ap, format);
/* Get the size of the formatted string by getting vsnprintf return the
* number of remaining characters if we ask it to write 0 characters */
int size = vsnprintf(NULL, 0, format, ap);
if (size > 0)
{
/* String formatted just fine */
result = (char *) calloc(size + 1, sizeof(char));
vsnprintf(result, size + 1, format, ap);
}
va_end(ap);
return result;
}我想不出在C90中做类似的事情的方法(没有vsnprintf)。如果不编写非常复杂的逻辑就无法实现,我很乐意为结果设置一个最大长度,但我不确定如何在不发生缓冲区溢出的情况下实现这一点。
发布于 2018-09-27 17:05:02
Pre-C99不提供简单的解决方案来格式化具有高度安全的防止缓冲区溢出的字符串。
正是那些烦人的"%s"、"%[]"、"%f"格式说明符需要如此仔细地考虑其潜在的长输出。因此,需要这样一种功能。@Jonathan Leffler
为了做到这一点,早期编译器要求代码分析format和参数以找到所需的大小。此时,代码几乎可以使您拥有完整的my_vsnprintf()。我会寻求解决这个问题的办法。@user694733 694733。
即使使用C99,*printf()也有环境限制。
任何一次转换可产生的字符数应至少为4095。C11dr§7.21.6.1 15
因此,任何试图使用char buf[10000]; snprintf(buf, sizeof buf, "%s", long_string);的代码都有可能出现问题,即使使用了足够的buf[],strlen(long_string) > 4095也是如此。
这意味着快速而肮脏的代码可以计算%和格式长度,并合理地假设所需的大小不超过:
size_t sz = 4095*percent_count + strlen(format) + 1;当然,对说明符的进一步分析可能会导致更保守的sz。继续写这个路径,我们结束在编写我们自己的my_vsnprintf()。
即使使用您自己的my_vsnprintf(),安全性也只有这么好。没有运行时检查format (可能是动态的)是否与以下参数匹配。要做到这一点,就需要采取一种新的办法。
厚颜无耻的C99解决方案的自我广告,以确保匹配的说明符和参数:通用。
https://stackoverflow.com/questions/52537188
复制相似问题