带有GCC的%s segfault的vsnprintf
vsnprintf with %s segfaults with GCC
我使用以下方法写入跟踪文件(灵感来自https://stackoverflow.com/a/16046064/283561)
void Tracing::Info( const char* content, ...)
{
va_list paramList;
va_start( paramList, content );
Tracing::AddRecord(boost::log::trivial::info, content, paramList);
va_end( paramList );
}
void Tracing::AddRecord(boost::log::trivial::severity_level sev, const char* content, va_list paramList)
{
int size = vsnprintf(0, 0, content, paramList) + 1;
if (size > 0)
{
boost::scoped_array<char> formattedString(new char[size]);
vsnprintf(formattedString.get(), size, content, paramList);
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> & lg = my_logger::get();
BOOST_LOG_SEV(lg, sev) << formattedString.get();
}
}
如果我在Linux(CentOS 7,GCC 4.8.2)下以以下方式调用该方法:
Tracing trace;
trace.Error("No %s root tag found!", rootTag.c_str());
它在AddRecord()中的vsnprintf的第二次调用时出错。
如果使用数字格式化程序(例如%i)调用它,它工作正常。我在Windows(VS2008/2010)下使用这些方法多年了,没有遇到任何问题。
我是不是遗漏了一些显而易见的东西?
不能像那样重用va_list
;您必须使用va_copy()
例程来创建新的va_list
实体,并在第二个vsprintf
上使用它;类似于:
void Tracing::AddRecord(boost::log::trivial::severity_level sev, const char* content, va_list paramList)
{
va_list parm_copy;
va_copy(parm_copy, paramList);
int size = vsnprintf(0, 0, content, paramList) + 1;
if (size > 0)
{
boost::scoped_array<char> formattedString(new char[size]);
vsnprintf(formattedString.get(), size, content, parm_copy);
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> & lg = my_logger::get();
BOOST_LOG_SEV(lg, sev) << formattedString.get();
}
va_end(parm_copy);
}
问题在于,在第一vsnprintf
中使用的操作va_arg
改变了va_list
的状态,使得其不能在第二vsnprintf
中原样使用。
使用一个小C程序可以很容易地看出这个问题。
#include <stdio.h>
#include <stdarg.h>
void
do_log(const char *item, va_list items)
{
#ifndef EVIL
va_list itemcopy;
va_copy(itemcopy, items);
#else
#define itemcopy items
#endif
int len = vsnprintf(0, 0, item, items);
if (len > 0) {
char buffer[2048];
vsnprintf(buffer, 2047, item, itemcopy);
printf("%sn", buffer);
}
va_end(itemcopy);
}
int
log_print(const char *item, ...)
{
va_list items;
va_start(items, item);
do_log(item, items);
va_end(items);
return 0;
}
int
main(int argc, char **argv)
{
log_print("These %d %d %d %d", 1, 2, 3, 4);
log_print("Hello %s %s", "Mike", argv[0]);
}
没有-DEVIL
,我得到:
These 1 2 3 4
Hello Mike ./vargs
如果我们用CFLAGS=-DEVIL
制作,我会得到输出(在OSX上):
These 4 0 0 1570641464
Hello
在其他平台上,它可能会崩溃。
相关文章:
- C++中带有List类的迭代器Segfault
- 使用Vulkan hpp vk::enumerateInstanceVersion()会导致segfault
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- std::partition segfault issue
- OpenSSL: EC_POINT_set_compressed_coordinates_GFp segfault
- 检查nullptr是否100%保护内存布局不受segfault影响
- OpenCV Tracker 属性访问在 ARM 上因 SEGFAULT 而失败,但在 X86_64 中工作
- 为什么优化大型 std::vector 数组会导致 SegFault?
- C++segfault,可重复的例子
- 带有zip_source_buffer的libzip会导致数据损坏和/或segfault
- 导致SegFault C++的析构函数
- 从引用的Vector获取SEGFAULT
- 尝试读取/写入Graphviz DAG值的工作证明会导致segfault
- Segfault如果更改派生类的指针值
- Microsoft VC++, vsnprintf, and Pipes (IO) Bug
- SegFault deleting QTreeWidgetItem
- vsnprintf 什么时候可以返回 0?
- PyImport_Import segfault
- 在函数结束后仅释放 Segfault 与 vsnprintf 一起消失
- 带有GCC的%s segfault的vsnprintf