Dalam semua skenario string-copy / move - strcat (), strncat (), strcpy (), strncpy (), dll. - semuanya berjalan lebih baik ( lebih aman ) jika beberapa heuristik sederhana diterapkan:
1. Selalu NUL-fill buffer Anda sebelum menambahkan data.
2. Deklarasikan buffer karakter sebagai [SIZE + 1], dengan konstanta makro.
Misalnya, diberikan:
#define BUFSIZE 10
char Buffer[BUFSIZE+1] = { 0x00 };
kita bisa menggunakan kode seperti:
memset(Buffer,0x00,sizeof(Buffer));
strncpy(Buffer,BUFSIZE,"12345678901234567890");
relatif aman. Memset () harus muncul sebelum strncpy (), meskipun kita menginisialisasi Buffer pada waktu kompilasi, karena kita tidak tahu sampah apa yang ditempatkan kode lain sebelum fungsi kita dipanggil. Strncpy () akan memotong data yang disalin menjadi "1234567890", dan tidak akan menghentikannya NUL. Namun, karena kita sudah mengisi NUL seluruh buffer - sizeof (Buffer), bukan BUFSIZE - tetap ada jaminan akan ada akhir "out-of-scope" yang menghentikan NUL, selama kita membatasi penulisan kita menggunakan BUFSIZE konstan, bukan sizeof (Buffer).
Buffer dan BUFSIZE juga berfungsi dengan baik untuk snprintf ():
memset(Buffer,0x00,sizeof(Buffer));
if(snprintf(Buffer,BUFIZE,"Data: %s","Too much data") > BUFSIZE) {
}
Meskipun snprintf () secara khusus hanya menulis BUFIZE-1 karakter, diikuti oleh NUL, ini bekerja dengan aman. Jadi kita "membuang" byte NUL yang asing di akhir Buffer ... kita mencegah kondisi buffer-overflow dan string yang tidak ditentukan, untuk biaya memori yang cukup kecil.
Panggilan saya di strcat () dan strncat () lebih tegas: jangan gunakan mereka. Sulit untuk menggunakan strcat () dengan aman, dan API untuk strncat () sangat berlawanan dengan intuisi sehingga upaya yang diperlukan untuk menggunakannya dengan benar meniadakan manfaat apa pun. Saya mengusulkan drop-in berikut:
#define strncat(target,source,bufsize) snprintf(target,source,"%s%s",target,source)
Sangat menggoda untuk membuat drop-in strcat (), tetapi bukan ide yang bagus:
#define strcat(target,source) snprintf(target,sizeof(target),"%s%s",target,source)
karena target mungkin sebuah pointer (sehingga sizeof () tidak mengembalikan informasi yang kita butuhkan). Saya tidak memiliki solusi "universal" yang baik untuk instance strcat () di kode Anda.
Masalah yang sering saya temui dari programmer "strFunc () - aware" adalah upaya untuk melindungi dari buffer-overflows dengan menggunakan strlen (). Ini bagus jika konten dijamin akan dihentikan NUL. Jika tidak, strlen () itu sendiri dapat menyebabkan kesalahan buffer-overrun (biasanya mengarah ke pelanggaran segmentasi atau situasi core-dump lainnya), sebelum Anda mencapai kode "bermasalah" yang Anda coba lindungi.