web-dev-qa-db-ja.com

sprintf()ではなくasprintf()を使用する理由

Asprintfが必要な理由を理解するのに苦労しています。ここにマニュアルでそれは言います

関数asprintf()およびvasprintf()は、sprintf(3)およびvsprintf(3)に類似していますが、 nullバイトを終了し、最初の引数を介してそれへのポインターを返します。割り当てられたストレージが不要になったときに解放するには、このポインターをfree(3)に渡す必要があります。

だからここに私が理解しようとしている例があります:

asprintf(&buffer, "/bin/echo %s is cool", getenv("USER"));

バッファが十分な大きさの文字列を割り当てた場合とchar * =(string)を言う場合の違いは何ですか

47
Brandon Ling

sprintf()またはvsprintf()を使用する場合、最初にバッファーを割り当てる必要があり、バッファーがsprintfが書き込む内容を格納するのに十分な大きさであることを確認する必要があります。それ以外の場合、sprintf()は、バッファーの末尾を超えたメモリをすべて上書きします。

char* x = malloc(5 * sizeof(char));
// writes "123456" +null but overruns the buffer
sprintf(x,"%s%s%s", "12", "34", "56");

... nullに割り当てられたスペースの終わりを超えて「6」と終了するxを書き込み、他の変数を破壊するか、セグメンテーションフォールトを引き起こします。

運が良ければ、割り当てられたブロックの間にあるメモリを踏みにじり、今度は害を与えません。これは断続的なバグにつながります-診断が最も難しい種類です。 ElectricFenceのようなツールを使用すると、オーバーランがフェイルファーストになります。

悪意のないユーザーが過度に長い入力を提供すると、プログラムが予期しない動作をする可能性があります。悪意のあるユーザーは、独自の実行可能コードをシステムに取り込む方法としてこれを悪用する可能性があります。

これに対する1つのガードは、snprintf()を使用することです。これは、指定した最大長にストリングを切り捨てます。

char *x = malloc(5 * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null

戻り値sizeは、スペースが利用可能な場合に必要だった書き込まれた長さです-終端のヌルを含まない

この場合、sizeが5以上の場合、切り捨てが発生したことがわかります。切り捨てが望ましくない場合は、新しい文字列を割り当ててsnprintf()を再試行できます。

char *x = malloc(BUF_LEN * sizeof(char));
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56");
if (size >= BUF_LEN) {
    realloc(&x,(size + 1) * sizeof(char));
    snprintf(x, size + 1 , "%s%s%s", "12", "34", "56");
}

(これはかなり単純なアルゴリズムですが、ポイントを示しています)

asprintf()はこれを1ステップで行います-文字列の長さを計算し、その量のメモリを割り当て、文字列を書き込みます。

char *x;
int size = asprintf(&x, "%s%s%s", "12", "34", "56");

いずれの場合でも、xを使い終わったら、それを解放するか、メモリをリークする必要があります。

free(x);

asprintf()は暗黙的なmalloc()であるため、malloc()または他のシステムコールの場合と同様に、動作を確認する必要があります。

if (size == -1 ) {
   /* deal with error in some way */
}

asprintf()は、GNUおよびlibcのBSD拡張の一部であることに注意してください。すべてのC環境で使用できるかどうかはわかりません。sprintf()およびsnprintf()はPOSIXおよびC99標準の一部です。

109
slim

利点はセキュリティです。

多数のプログラムにより、ユーザー提供のデータでいっぱいになったときにプログラマー提供のバッファーがオーバーフローすることにより、システムの悪用が可能になりました。

asprintfがバッファを割り当てることにより、発生しないことが保証されます。

ただし、mustasprintfの戻り値をチェックして、メモリ割り当てが実際に成功したことを確認します。 http://blogs.23.nu/ilja/2006/10/antville-12995/ を参照してください

20
Alnitak