3

Cppcheck 1.67により、ソース コードの次の行で移植性の問題が発生しました。

sscanf(s, "%d%*[,;.]%d", &f, &a);

これは私がそこから得たメッセージです:

libc の一部のバージョンでは、フィールド幅制限のない scanf は巨大な入力データでクラッシュする可能性があります。

フォーマット文字列の当初の意図は、2 つの整数の間の 3 つの可能なリミッター文字のうちの 1 つを受け入れることでしたが、今日では - Cppcheck [1]のおかげで -%*[,;.]リミッター文字の文字列さえも受け入れることがわかりました。ただし、無制限の部分が無視されるため、フォーマット文字列がクラッシュを引き起こす可能性があるとは思えません。

バッファ オーバーランに問題がある可能性はありますか? …もしかして裏方?


[1] 遠視と失明の間で迷子になる方法:

%1*[,;.](いくつかの API doc の後) で修正しようとしましたが、Cppcheck が問題を主張したため%*1[,;.]、同じ「成功」で試しました。とりあえず抑えないといけないようですが…

4

2 に答える 2

1

C sscanf関数で無視されたパターンマッチを定量化するのはいつですか?

おそらく、常に定量化するのは良い考えですが (以下を参照)、定量化しすぎると、意図から逸れてしまう可能性もあります。上記の場合、単一の区切り文字をスキップする必要がある場合、数量化は間違いなく役立ちます。

バッファ オーバーランに問題がある可能性はありますか? …もしかして裏方?

コードが原因でクラッシュすることはありません。「舞台裏」の質問に対処するために、大きな入力文字列を試してみました。テストした C ライブラリでは、内部バッファ オーバーフローはありませんでした。Borland C++ 5.6.4 に同梱されている C ライブラリを試してみたところ、大量の入力 (4 億文字以上) ではバッファ オーバーランをトリガーできないことがわかりました。

驚くべきことに、Cppcheck は完全に間違っていたわけではありません。移植性の問題がありますが、別の問題があります。

#include <stdio.h>
#include <assert.h>
#include <sstream>

int traced_sscanf_set(const int count, const bool limited)
{
    const char sep = '.';
    printf("\n");
    std::stringstream ss;
    ss << "123" << std::string(count, sep) << "456";
    std::string s = ss.str();
    printf("string of size %d with %d '%c's in it\n", s.size(), count, sep);
    std::stringstream fs;
    fs << "%d%";
    if (limited) {
        fs << count;
    }
    fs << "*["<< sep << "]%d";
    std::string fmt = fs.str();
    printf("fmt: \"%s\"\n", fmt.c_str());
    int a = 0;
    int b = 0;
    const sscanfResult = sscanf(s.c_str(), fmt.c_str(), &a, &b);
    printf("sscanfResult=%d, a=%d, b=%d\n", sscanfResult, a, b);
    return sscanfResult;
}

void test_sscanf()
{
    assert(traced_sscanf_set(0x7fff, true)==2);
    assert(traced_sscanf_set(0x7fff, false)==2);
    assert(traced_sscanf_set(0x8000, true)==2);
    assert(traced_sscanf_set(0x8000, false)==1);
}

私がチェックしたライブラリは、フォーマットパラメータに明示的に指定された制限がない場合、内部的に消費される (そしてスキップされる) 入力を 32767 (2 15 -1) 文字に制限します。

興味のある方のために、トレース出力を次に示します。

string of size 32773 with 32767 '.'s in it
fmt: "%d%32767*[.]%d"
sscanfResult=2, a=123, b=456

string of size 32773 with 32767 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=2, a=123, b=456

string of size 32774 with 32768 '.'s in it
fmt: "%d%32768*[.]%d"
sscanfResult=2, a=123, b=456

string of size 32774 with 32768 '.'s in it
fmt: "%d%*[.]%d"
sscanfResult=1, a=123, b=0
于 2014-10-28T12:17:24.110 に答える