2016-03-23 11 views
3

MSVCの最新セキュリティアップデートに準拠するために、「レガシー」コードを更新しようとしています。_vsnprintfから_vsnprintf_sに移行する際に問題が発生しています。セキュリティで保護された_vsnprintf_sで必要なバッファ長を取得する

特に、私は、数/長さヌルバッファとゼロ_vsnprintfを呼び出す結果を取得、必要なサイズ(return value + 1)のバッファを割り当て、その後、新たに割り当てられたバッファで再度_vsnprintfを呼び出しました既知の正しいサイズ:

size_t length = _vsntprintf(nullptr, 0, mask, params); 
TCHAR *final = new TCHAR [length + 1]; 
_vsntprintf(final, length + 1, mask, params); 

この動作はdocumented on MSDNです:

countで指定されたバッファサイズがフォーマットとARGPTRで指定された出力を含むのに十分な大きさでない場合は、 vsnprintfの戻り値は、countが十分に大きい場合に書き込まれる文字数です。戻り値がcount - 1より大きい場合、出力は切り捨てられています。

と同じことをしようとしていますが、its documentation does not contain the sameです。データを格納するために必要なストレージと終端のヌルがsizeOfBufferを超えた場合には文字列ではなく、その場合に限り、パラメーターの検証に記載されたカウントが_TRUNCATEでない限り、無効なパラメータハンドラは、呼び出され、

を語りますbufferに収まるように書かれ、-1が返されます。以下でとにかくそれを試し

size_t length = _vsntprintf_s(nullptr, 0, 0, mask, params); 

これがゼロの "長さ" になります。回数ではなく、以下のアサーションが失敗したとして、あなたが_TRUNCATE(-1)に渡した場合:

式:!> 0

バッファ= nullptr & & BUFFER_COUNTを私は_set_invalid_parameter_handlerを上書きすることが可能であると推定しますどのように長さがあるべきかを見いだすが、より簡単な方法が必要ですか?

+0

これは何のCコードではありませんが。 – Olaf

+0

@Olaf申し訳ありませんが、それはC++だったはずです。私はその誤植を逃した 'security-enhanced-crt'タグについて心配していました。あなたは本当にそれがdownvotingの価値があったと思いますか? –

+0

'size_t length = _vsntprintf(nullptr、0、0、mask、params)'の行で、 '_vsntprintf_s'を意味しましたか? – TriskalJM

答えて

6
size_t length = _vscprintf(mask, va_list); 
TCHAR *final = new TCHAR [length + 1]; 
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list); 
+1

それは完璧です。素晴らしい、きれいな解決策。 '_vscprintf'は、' _vsnprintf_s'ページimhoに文書化されるべきです。 –

-1

どのように長さを取得するために、「規則に違反しない」独自のvsnprintfバリアントを転がりについて:[最も可能性が高い]あなたはsizeof(buf)未満でなければならないことが返さので

int 
printf_size(const char *fmt,int count,va_list ap) 
{ 
    char buf[2000000]; 
    int len; 

    len = vsnprintf_s(buf,sizeof(buf),count,fmt,ap); 

    return len; 
} 

を良い。

かは、実行します。

int 
printf_size(const char *fmt,int count,va_list ap) 
{ 
    char *buf; 
    int siz; 
    int len; 

    for (siz = 2000000; ; siz <<= 1) { 
     buf = malloc(siz); 
     len = vsnprintf_s(buf,siz,count,fmt,ap); 
     free(buf); 
     if (len < siz) 
      break; 
    } 

    return len; 
} 

あるいは、ワンストップショップ機能実行:

int 
sprintf_secure(char **buf,const char *fmt,int count,va_list ap) 
{ 
    char *bp; 
    int siz; 
    int len; 

    for (siz = 2000000; ; siz <<= 1) { 
     bp = malloc(siz); 
     len = vsnprintf_s(bp,siz,count,fmt,ap); 
     if (len < siz) 
      break; 
    } 

    bp = realloc(bp,len + 1); 

    *buf = bp; 

    return len; 
} 
+0

提案してくれてありがとうが、誰かが私の機能を呼び出すたびに4MiBのデータを無作為に割り振るのはちょっとした過労です。 –

+0

さて、最初のスタックバージョンを使用してください。割り当てはありません。 2MBのバッファ[10,000は十分にあるはずです]では、最大スタック制限を超えてはなりません。または、sprintf_secureですが、1000(または100)から始まります。使用されている実際の長さを見て動的に調整できるチューニングパラメータです。あなたのコメントに基づいて、私はちょうど '* cprintf'が同じ理由で使用できなくなると仮定しました。さもなければ私はおそらく答えを投稿していないでしょう。 –

+0

いいえ。セキュアなcrt関数は、事前に割り当てられたバッファへの書き込みを伴う操作のみを置き換えます。整数を返すvscprintfのような関数は影響を受けません。 –

関連する問題