6

MSVC の最新のセキュリティ更新プログラムに準拠するように「レガシー」コードを更新しようとしていますが、 から_vsnprintfへの移行で問題に直面してい_vsnprintf_sます。

具体的には_vsnprintf、null バッファーとカウント/長さのゼロで呼び出し、結果を取得し、必要なサイズ ( ) のバッファーを割り当ててから、新しく割り当てられたバッファーと既知の正しいサイズで再度return value + 1呼び出していました。_vsnprintf

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

この動作は、MSDN で文書化されています

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

で同じことをしようとしています_vsnprintf_sが、そのドキュメントには同じが含まれていません。代わりに言う

データを格納するために必要なストレージと終端の null が sizeOfBuffer を超える場合、count が _TRUNCATE でない限り、パラメーターの検証で説明されているように、無効なパラメーター ハンドラーが呼び出されます。 1 が返されました。

とにかく次の方法で試してみてください:

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

これにより、「長さ」がゼロになります。_TRUNCATE代わりに (-1) をカウントとして渡すと、次のアサーションは失敗します。

式: buffer != nullptr && buffer_count > 0

オーバーライド_set_invalid_parameter_handlerして、どうにかして長さを調べることは可能だと思いますが、もっと簡単な方法が必要ですか?

4

2 に答える 2

-1

vsnprintf長さを取得するために「ルールに違反」しない独自のバリアントをローリングするのはどうですか:

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

返される金額は [ほとんどの場合] 少なくなるため、sizeof(buf)問題ありません。

または、次のようにします。

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;
}
于 2016-03-23T23:00:16.827 に答える