問題の歴史
安全なメモリコピーは、Cにおける最も一般的かつ重要なタスクの一つです。最初は、プログラムはバイトごとのコピーのためのループを使用していました。その後、標準関数として memcpy や memmove といった関数が追加され、文字列用のより安全な代替手段として strncpy が導入されました。不適切なコピーはバッファオーバーフローや脆弱性を引き起こします。
問題
不適切な関数の使用や不正なサイズでのコピーは、データを破壊したり、セキュリティに関心のある第三者へのアクセスを許したりする可能性があります。memmove を使うべき場合と memcpy を使うべき場合を区別することは、重複したメモリ領域に関連するエラーを避けるために非常に重要です。
解決策
非文字列メモリの安全なコピーには次のように使用します:
memcpy(dest, src, n);
memcpy は、src から dest に n バイトを迅速にコピーしますが、メモリ領域が重複しない場合に限ります。memmove を使用します:memmove(dest, src, n);
文字列をコピーするためには、strncpy または、可能であれば現代的かつ安全な代替手段である strlcpy を使用するのが理想です。
主な特徴:
memcpy は、src と dest の重複がない場合にのみ安全です。memmove は、重複したメモリ領域に対しても正しく動作します。1. memcpy と memmove の違いは何で、どのような場合にどちらの関数が必要ですか?
memcpy は非常に高速ですが、重複するメモリ領域に対しては設計されていません - 結果は予測不可能になります。memmove は、重複があっても正確なコピーを保証します:
int arr[] = {1,2,3,4,5}; // memmove: 重複して安全にコピーします memmove(arr+1, arr, 4 * sizeof(int));
2. より小さいバッファに文字列をコピーするために strcpy を使用することは安全ですか?
いいえ、strcpy 関数は宛先バッファのサイズを確認しません。これはしばしばバッファオーバーフローを引き起こします。strncpy または strlcpy(利用可能な場合)を使用するか、サイズを明示的に制御する方が良いです:
char dest[5]; strncpy(dest, src, sizeof(dest)-1); // src は 5 文字未満である必要があります
3. ポインタを持つ構造体をコピーするために memcpy を使用できますか?
はい、しかしこれはポインタそのものだけをコピーし、そのアドレスのデータはコピーしません。これにより、メモリを操作する際にエラーが発生したり、二重解放が発生する可能性があります。
長い文字列を小さなバッファに対して長さをチェックせずに strcpy を使用してコピーします。これによりバッファオーバーフローが発生し、脆弱性が生じます。
利点:
欠点:
strncpy または memmove を使用してサイズを正確に制御し、手動で文字列のヌルターミネータを保証します。
利点:
欠点: