我有以下日志功能:
template<typename... Arguments>
void Log(const char* file, const int line, int level, const char* fmt, Arguments... args)
{
std::string formattedFile;
if (file)
{
boost::filesystem::path p(file);
formattedFile = p.filename().string();
}
std::string message{boost::str(boost::format("%1%:%2% [%3%] - %s") % formattedFile % line % m_uxid % fmt)};
__android_log_print(level, m_tag.c_str(), message.c_str(), args...);
}
此应用程序使用NDK在Android上运行,因此这是该平台的日志记录系统。问题是__android_log_print()
无法编译:
error: format not a string literal and no format arguments [-Werror=format-security]
__android_log_print(level, m_tag.c_str(), message.c_str(), std::forward<Arguments>(args)...);
^
我不确定这意味着什么。我没有正确使用variadic模板参数吗?
答案 0 :(得分:0)
printf
中不受信任的输入可能是一个安全问题。使用字符串文字强制执行格式是提高安全性的一种方法
将警告转换为错误将导致构建失败,因此您不得不解决警告。
海湾合作委员会warning options有这个说法
-Werror
:
将所有警告变为错误。
-Wformat-security
:
关于使用表示可能出现的安全问题的格式函数的警告
目前,这会警告调用printf和scanf函数,其中格式字符串不是字符串文字并且没有格式参数
如果格式字符串来自不受信任的输入并包含%n
,则这可能是一个安全漏洞。
通常建议在函数中创建std::string
并将%s
格式字符串文字传递给日志函数
__android_log_print(level, m_tag.c_str(), "%s", message.c_str());
从处理args...
构建消息的位置,通常使用boost::format
或std::stringstream
之类的内容。
如果要使用提供的fmt
字符串和可变参数args,可以使用自定义printf
样式函数解析参数,该函数生成std::string
std::string va_string_printf(const char* format, va_list ap)
{
char stack_buf[256];
char* buf = stack_buf;
int buf_size = sizeof(stack_buf);
std::string out_str;
while(true)
{
va_list ap1;
va_copy(ap1, ap);
int min_buf_size = vsnprintf(buf, buf_size, format, ap1) + 1;
va_end(ap1);
if (min_buf_size > buf_size)
{
if (buf != stack_buf) // allocate a bigger buffer
delete[] buf;
buf = new char[min_buf_size];
buf_size = min_buf_size;
continue;
}
out_str = buf;
break;
}
if (buf != stack_buf)
delete[] buf;
return out_str;
}
std::string string_printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
std::string str = va_string_printf(format, ap);
va_end(ap);
return str;
}