CrHasher
CrHasher

Reputation: 343

Simple logger class vsnprintf is crashing with read access violation

While implementing a simple printf style logger I encountered a vsnprintf crash. This is how I call the logger utility:

LoggerUtil->LogInfo("Whatever info here %s", "just a test!");

It calls a function with a variable number of arguments. The idea is to add extra information to the format string so I need to change 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 :(
    ...
}

Can't figure out the main problem, not tempering with fmt solves the problem but it's not an option:

void LoggerUtil::LogInfo(const char* fmt, ...)
{
    va_list arg_list;
    va_start(arg_list, fmt);
    Logger::InfoVA(fmt, arg_list);
    va_end(arg_list);
}

What am I missing here?

Upvotes: 0

Views: 1577

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597166

After using LogClientInfo() to create a new format string, you are then passing the wrong input value to the second parameter to va_start(). You are passing your local format variable, but you need to pass the fmt argument of LogInfo() instead. Just because you are using a different format string when calling Logger::InfoVA() does not change where the input format values are stored. va_start() configures the va_list to point at the next function argument relative to the specified argument, and in this case that needs to be the fmt function argument, not the local format variable:

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);
}

Upvotes: 2

Related Questions