24

このパターンを使用して、作業中のコードの文字列に連結するのを見ました。

sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id);
sprintf(buffer, "%s</td>", buffer);

そして私はそれが安全ではないとかなり確信していますC.あなたはそれbufferが出力と最初の入力の両方であることに気付くでしょう。

バッファオーバーフローの明らかな可能性は別として、関数の開始と終了の間でバッファが変更されないという保証はないと思います(つまり、バッファの状態が関数の実行)。sprintfのシグニチャは、ターゲット文字列がrestrictedであることを追加で指定します。

memcpyでの投機的な記述の報告も思い出しますが、一部のCライブラリがsprintfで同じことを行う理由はわかりません。この場合、もちろん、それはそのソースに書き込みます。では、この動作は安全ですか

参考までに、私は提案しました:

char *bufEnd = buffer + strlen(buffer);
/* sprintf returns the number of f'd and print'd into the s */
bufEnd += sprintf(bufEnd, " <input type='file' name='%s' />\r\n", id);

これを交換します。

4

3 に答える 3

24

glibc sprintf()ドキュメントから:

オーバーラップするオブジェクト間でコピーが行われる場合、たとえば、'%s'変換の制御下で出力される引数としてsも指定されている場合、この関数の動作は定義されていません。

特定の実装では安全な場合があります。しかし、あなたはそれがポータブルであることを期待することはできませんでした。

あなたの提案がすべての場合において安全であるかどうかはわかりません。まだバッファが重複している可能性があります。遅く、妻は私を悩ませていますが、連結された文字列で元の文字列を再び使用したい場合があり、ヌル文字を上書きしているため、sprintf実装は再利用された場所を知らない可能性があります文字列が終了します。

snprint()を一時バッファーに固定してから、strncat()を元のバッファーに貼り付けたい場合があります。

于 2009-08-16T02:58:21.423 に答える
5

この特定のケースでは、文字列inbufferが最初に入力されるbufferため(これも役に立たない)、strcat()代わりに使用して[ほぼ]同じ効果を得ることができます。

ただし、strcat()のフォーマットの可能性と組み合わせようとしている場合は、次のsprintf()ことを試してみてください。

sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
于 2009-08-16T03:13:00.047 に答える
3

printf()を使用してフォーマットされたテキストをバッファの最後に連結する場合は、整数を使用して終了位置を追跡することをお勧めします。

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
i += sprintf(&buffer[i], "</td>");

また:

int i = strlen(buffer);
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id);
strcat(&buffer[i], "</td>");

そして、人々がこれに反対票を投じる前に(「これは安全ではありません!バッファをオーバーランできます!」)、C /C++でフォーマットされた文字列を作成する合理的な方法に取り組んでいます。

于 2009-08-16T03:27:58.560 に答える