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
書き込まれる長さであり、終了nullは含まれません。
この場合、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 */
}
これはlibcのGNUおよびBSD拡張機能の一部であることに注意してくださいasprintf()
。すべてのC環境で使用できるかどうかはわかりません。sprintf()
およびsnprintf()
はPOSIXおよびC99標準の一部です。