在C程序中,我有一个将消息写入日志文件的函数
LogResult writeLog(const char* format, ...)
该函数将其参数传递给'vfprintf()'作为'format'字符串和'va_list'。我突然意识到,如果有人传递未终止的字符串,我无法控制会发生什么,例如。
const char unterminatedString[5] = {'h', 'e', 'l', 'l', 'o'};
writeLog("Log message: %s", unterminatedString);
有没有办法防范这个?
答案 0 :(得分:2)
还有许多其他方法(在你提到的那个方面)传递非法字符串。
一些例子:
char* unterminatedString;
writeLog("Log message: %s", unterminatedString);
char* unterminatedString = (char*)0xA5A5A5A5;
writeLog("Log message: %s", unterminatedString);
char unterminatedString[] = "abc";
unterminatedString[3] = 'd';
writeLog("Log message: %s", unterminatedString);
int x = -1;
char* unterminatedString = (char*)&x;
writeLog("Log message: %s", unterminatedString);
合法字符串必须从有效的内存地址开始,并以有效的内存地址结束(带0字符)。没有明确的方法断言,除了迭代字符串本身,直到达到0字符或执行内存访问冲突(这正是vfprintf
函数的作用)。
答案 1 :(得分:2)
const char*
不知道数组的长度,它只是一个地址。所以这不是简单的可能。
如果你想保持纯C,你可以传递字符串的长度int len
作为额外的参数,并检查是否format[len]==0
。
我不认为这有用,但在我看来更糟糕。
由于您使用C ++标记了此问题,因此您可以(并且应该)使用std::string
:
LogResult writeLog(const std::string& format, ...)
始终正确终止std::string
,您可以使用std::string::c_str()
访问其基础C风格字符串。
请注意,std::string
可以存储\0
- 字符,因此使用C风格字符串的函数将停在第一个\0
,而不是std::string
的末尾}。
答案 2 :(得分:2)
我假设你的日志功能有自己的内部缓冲区,你知道它的大小。
然后,您可以使用指定缓冲区大小的vsprintf()函数。请参阅Possible buffer overflow vulnerability。
答案 3 :(得分:1)
不,没有办法可以轻易做到。
您可以做的是使用valgrind
等工具查找此类错误。