C++ 简单记录器类vsnprintf因读访问冲突而崩溃

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

在实现一个简单的printf样式的记录器时,我遇到了一个vsnprintf崩溃。这是我如何调用logger实用程序的:

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,所以我将使用可变模板重写所有内容。我不想再次用这些违反直觉的变量列表攻击我自己。