2016-12-15 17 views
0

シンプルなprintfスタイルのロガーを実装しているときに、vsnprintfクラッシュが発生しました。これは、私がロガーユーティリティを呼び出す方法です:シンプルなロガークラスvsnprintfが読み取りアクセス違反でクラッシュする

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

私はここで何が欠けていますか?

+1

私はすぐに問題が表示されません。 purifyやvalgrindなどのメモリ計測ツールを使用して、メモリの破損を検索します。ある特定の関数でC++プログラムがクラッシュしたとしても、そのバグはどこにあるのか分かりません。 –

+0

'va_start(arg_list、format);'私はそれが 'va_start(arg_list、fmt);でなければならないと思うあなたは私が得ることができないトリッキーなことをしようとしていない限り。しかし、基本的にあなたは 'va_start'を他の場所でderoutしています。==> UB。私はあなたのコード内のすべての可能性のある問題を修正しているとは確信していないので、これを回答として投稿しませんでした。 –

+0

'C++ 'を使っているので、[可変引数テンプレート](http://en.cppreference.com/w/cpp/language/parameter_pack)を使うなど、可変数の引数を実装する方がはるかに優れています。次に、va_start、va_argなどでこの混乱に陥ることはありません。リンクのサンプルコードを参照してください。 – PaulMcKenzie

答えて

2

LogClientInfo()を使用して新しいフォーマット文字列を作成した後、2番目のパラメータに間違った入力値をva_start()に渡しています。ローカルのformat変数を渡していますが、代わりにfmt引数をLogInfo()に渡す必要があります。 Logger::InfoVA()を呼び出すときに別の書式文字列を使用しているだけで、入力書式の値の格納場所は変わりません。 va_start()は、指定された引数に対する次関数の引数を指すようにva_listを構成し、fmt関数の引数ではなく、ローカルformat変数である必要があり、この場合には:

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

私はあなたにとても感謝しています。va_start(arg_list、format)を変更しました。 〜va_start(arg_list、fmt);私の問題を解決しました。どうもありがとうございました!とにかく私はC++ 14を使用していますので、私はすべてのバリデーショナルテンプレートを書き直します。これらの直感的なva_listを使って足で自分自身を撃ってはいけません。 – CrHasher

関連する問題