C++ 简单记录器类vsnprintf因读访问冲突而崩溃
在实现一个简单的printf样式的记录器时,我遇到了一个vsnprintf崩溃。这是我如何调用logger实用程序的:C++ 简单记录器类vsnprintf因读访问冲突而崩溃,c++,crash,printf,C++,Crash,Printf,在实现一个简单的printf样式的记录器时,我遇到了一个vsnprintf崩溃。这是我如何调用logger实用程序的: LoggerUtil->LogInfo("Whatever info here %s", "just a test!"); 它调用具有可变参数数的函数。想法是向格式字符串添加额外信息,因此我需要更改fmt: std::string LoggerUtil::LogClientInfo(const char* fmt) { return "Some info her
LoggerUtil->LogInfo("Whatever info here %s", "just a test!");
它调用具有可变参数数的函数。想法是向格式字符串添加额外信息,因此我需要更改fmt:
std::string LoggerUtil::LogClientInfo(const char* fmt)
{
return "Some info here %s";
}
void LoggerUtil::LogInfo(const char* fmt, ...)
{
std::string formatStr = LogClientInfo(fmt); // returns "Some info here %s" just for testing altering the format string
const char* format = formatStr.c_str(); // checked memory and its '\0' terminated string
va_list arg_list;
va_start(arg_list, format);
Logger::InfoVA(format, arg_list);
va_end(arg_list);
}
void Logger::InfoVA(const char* fmt, va_list arg_list)
{
Log(Priority_Info, fmt, arg_list);
}
void Logger::Log(Priority priority, const char* fmt, va_list args)
{
char str[MaxLogEntrySize];
memset(str,0,MaxLogEntrySize*sizeof(char));
vsnprintf(str,MaxLogEntrySize-1, fmt, args); // CRASH :(
...
}
无法找出主要问题,不使用fmt回火可以解决问题,但这不是一个选项:
void LoggerUtil::LogInfo(const char* fmt, ...)
{
va_list arg_list;
va_start(arg_list, fmt);
Logger::InfoVA(fmt, arg_list);
va_end(arg_list);
}
这里缺少什么?在使用
LogClientInfo()
创建新的格式字符串后,您将错误的输入值传递到第二个参数va_start()
。您正在传递本地format
变量,但需要传递LogInfo()
的fmt
参数。仅因为在调用Logger::InfoVA()
时使用了不同的格式字符串,所以不会更改输入格式值的存储位置va_start()
将va_列表
配置为指向相对于指定参数的下一个函数参数,在这种情况下,它需要是fmt
函数参数,而不是本地格式
变量:
void LoggerUtil::LogInfo(const char* fmt, ...)
{
std::string formatStr = LogClientInfo(fmt);
va_list arg_list;
va_start(arg_list, fmt); // <-- use fmt here !
Logger::InfoVA(formatStr.c_str(), arg_list);
va_end(arg_list);
}
void LoggerUtil::LogInfo(const char*fmt,…)
{
std::string formatStr=LogClientInfo(fmt);
va_列表arg_列表;
va_start(arg_list,fmt);//在使用LogClientInfo()
创建新的格式字符串后,将错误的输入值传递给va_start()
的第二个参数。将传递本地format
变量,但需要传递LogInfo()的fmt
参数
而不是。仅仅因为在调用Logger::InfoVA()
时使用了不同的格式字符串,所以不会更改输入格式值的存储位置。va\u start()
将va_列表
配置为指向相对于指定参数的下一个函数参数,在这种情况下,它需要是fmt
函数参数,而不是本地格式
变量:
void LoggerUtil::LogInfo(const char* fmt, ...)
{
std::string formatStr = LogClientInfo(fmt);
va_list arg_list;
va_start(arg_list, fmt); // <-- use fmt here !
Logger::InfoVA(formatStr.c_str(), arg_list);
va_end(arg_list);
}
void LoggerUtil::LogInfo(const char*fmt,…)
{
std::string formatStr=LogClientInfo(fmt);
va_列表arg_列表;
VAYSTART(ARGSLIST,FMT);//我不立即看到问题。使用内存工具工具,如Purialor或ValGrand,来搜索内存损坏。仅仅因为C++程序在一个特定函数中崩溃并不意味着bug在哪里。<代码> VAXSTART(ARGYLIST,FREST);< /Cord> >我猜应该是<代码> VAYSTART(AgSLIST,FMT)
除非你试图做一些我无法得到的棘手的事情。但基本上你是在其他地方去路由va_start
,==>UB。我没有把这作为一个答案,因为我不确定它是否解决了你代码中所有可能的问题。因为你使用的是C++
有更好的方法来实现可变数量的参数nts,例如使用。这样你就不会陷入va_start、va_arg等的混乱中。请参阅链接上的示例代码。@PaulMcKenzie:Remy的回答暂时解决了我的问题,但我将根据你发送的示例重写代码,谢谢!我没有立即看到问题。使用内存检测工具,如purify或valgrind,来搜索对于内存损坏。仅仅因为C++程序在一个特定函数中崩溃并不意味着bug所在。<代码> VAXSTART(ARGYLIST,FALSE);< /Cord> >我猜应该是<代码> VAYSTART(AgSLIST,FMT)
除非你试图做一些我无法得到的棘手的事情。但基本上你是在其他地方去路由va_start
,==>UB。我没有把这作为一个答案,因为我不确定它是否解决了你代码中所有可能的问题。因为你使用的是C++
有更好的方法来实现可变数量的参数nts,例如使用。这样你就不会陷入va_start、va_arg等的混乱。请参阅链接上的示例代码。@PaulMcKenzie:Remy的回答暂时解决了我的问题,但我将根据你发送的示例重写代码,谢谢!我非常感谢你,将va_start(arg_list,format)更改为va_start(arg_list,fmt);解决了我的问题。非常感谢!不管怎样,我使用的是C++14,所以我会用可变模板重写所有内容。我不想再次用这些反直觉的变量列表攻击我自己。我非常感谢你,将变量开始(arg_list,format);更改为变量开始(arg_list,fmt);解决了我的问题。非常感谢!无论如何,我使用的是C++14,所以我将使用可变模板重写所有内容。我不想再次用这些违反直觉的变量列表攻击我自己。