Saya telah membaca di Stack Overflow bahwa beberapa fungsi C "usang" atau "harus dihindari". Bisakah Anda memberi saya beberapa contoh fungsi semacam ini dan alasannya?
Alternatif apa untuk fungsi tersebut yang ada?
Bisakah kita menggunakannya dengan aman - ada praktik yang baik?
c
standard-library
obsolete
Andrei Ciobanu
sumber
sumber
strncpy()
sebagai pengganti umum untukstrcpy()
, dan saya tidak akanstrncat()
pernah menggunakannya karena memiliki antarmuka paling tidak intuitif yang bisa dibayangkan - apakah ANDA tahu apa yang ditentukan oleh parameter panjang?Jawaban:
Deprecated Functions
Insecure
Contoh sempurna dari fungsi tersebut adalah gets () , karena tidak ada cara untuk mengatakan seberapa besar buffer tujuan. Akibatnya, program apa pun yang membaca input menggunakan gets () memiliki kerentanan buffer overflow . Untuk alasan serupa, seseorang harus menggunakan strncpy () sebagai ganti strcpy () dan strncat () sebagai ganti strcat () .
Namun beberapa contoh lainnya termasuk fungsi tmpfile () dan mktemp () karena potensi masalah keamanan dengan menimpa file - file sementara dan yang digantikan oleh fungsi mkstemp () yang lebih aman .
Non-Reentrant
Contoh lain termasuk gethostbyaddr () dan gethostbyname () yang non-reentrant (dan, oleh karena itu, tidak dijamin sebagai threadsafe) dan telah digantikan oleh reentrant getaddrinfo () dan freeaddrinfo () .
Anda mungkin memperhatikan pola di sini ... baik kurangnya keamanan (mungkin karena gagal menyertakan cukup informasi dalam tanda tangan untuk menerapkannya dengan aman) atau tidak masuk kembali adalah sumber umum penghentian.
Kedaluwarsa, Tidak Portabel
Beberapa fungsi lain menjadi tidak digunakan lagi karena mereka menggandakan fungsionalitas dan tidak portabel seperti varian lainnya. Misalnya, bzero () tidak digunakan lagi untuk mendukung memset () .
Keamanan dan Masuk Kembali Thread
Anda bertanya, dalam postingan Anda, tentang keamanan dan akses masuk kembali thread. Ada sedikit perbedaan. Sebuah fungsi reentrant jika tidak menggunakan status bersama yang bisa berubah. Jadi, misalnya, jika semua informasi yang dibutuhkan diteruskan ke dalam fungsi, dan semua buffer yang diperlukan juga diteruskan ke fungsi (bukan dibagikan oleh semua panggilan ke fungsi), maka itu adalah reentrant. Itu berarti bahwa utas yang berbeda, dengan menggunakan parameter independen, tidak mengambil risiko status berbagi secara tidak sengaja. Reentrancy adalah jaminan yang lebih kuat daripada keamanan benang. Sebuah fungsi aman untuk thread jika dapat digunakan oleh beberapa thread secara bersamaan. Suatu fungsi aman untuk thread jika:
Secara umum, dalam Spesifikasi UNIX Tunggal dan IEEE 1003.1 (yaitu "POSIX"), fungsi apa pun yang tidak dijamin sebagai reentrant tidak dijamin aman untuk thread. Jadi, dengan kata lain, hanya fungsi yang dijamin reentrant yang dapat digunakan secara portabel dalam aplikasi multithread (tanpa penguncian eksternal). Namun, itu tidak berarti bahwa penerapan standar ini tidak dapat memilih untuk membuat fungsi non-reentrant aman untuk thread. Misalnya, Linux sering menambahkan sinkronisasi ke fungsi non-reentrant untuk menambahkan jaminan (di luar Spesifikasi UNIX Tunggal) dari threadsafety.
Strings (dan Memory Buffer, secara Umum)
Anda juga ditanya apakah ada beberapa kelemahan mendasar dengan string / array. Beberapa orang mungkin berpendapat bahwa ini masalahnya, tetapi saya berpendapat bahwa tidak, tidak ada kekurangan mendasar dalam bahasa tersebut. C dan C ++ mengharuskan Anda meneruskan panjang / kapasitas larik secara terpisah (ini bukan properti ".length" seperti dalam beberapa bahasa lain). Ini bukan cacat, per-se. Setiap pengembang C dan C ++ dapat menulis kode yang benar hanya dengan meneruskan panjang sebagai parameter jika diperlukan. Masalahnya adalah beberapa API yang membutuhkan informasi ini gagal menetapkannya sebagai parameter. Atau diasumsikan bahwa beberapa konstanta MAX_BUFFER_SIZE akan digunakan. API semacam itu sekarang sudah tidak digunakan lagi dan diganti dengan API alternatif yang memungkinkan ukuran array / buffer / string ditentukan.
Scanf (Menjawab Pertanyaan Terakhir Anda)
Secara pribadi, saya menggunakan pustaka C ++ iostreams (std :: cin, std :: cout, operator << dan >>, std :: getline, std :: istringstream, std :: ostringstream , dll.), jadi saya biasanya tidak berurusan dengan itu. Jika saya terpaksa menggunakan C murni, saya pribadi hanya akan menggunakan fgetc () atau getchar () dalam kombinasi dengan strtol () , strtoul () , dll. Dan mengurai hal-hal secara manual, karena saya bukan penggemar berat varargs atau format string. Karena itu, sejauh pengetahuan saya, tidak ada masalah dengan [f] scanf () , [f] printf (), dll. selama Anda membuat string format sendiri, Anda tidak pernah melewatkan string format arbitrer atau mengizinkan input pengguna untuk digunakan sebagai string format, dan Anda menggunakan makro pemformatan yang ditentukan di <inttypes.h> jika sesuai. (Catatan, snprintf () harus digunakan sebagai pengganti sprintf () , tetapi itu berkaitan dengan kegagalan menentukan ukuran buffer tujuan dan bukan penggunaan string format). Saya juga harus menunjukkan bahwa, di C ++, boost :: format menyediakan format seperti printf tanpa varargs.
sumber
strncpy
umumnya juga harus dihindari. Itu tidak melakukan apa yang diasumsikan oleh sebagian besar programmer. Itu tidak menjamin penghentian (menyebabkan buffer overruns), dan itu mengisi string yang lebih pendek (mungkin menurunkan kinerja dalam beberapa kasus).strncpy()
atau bahkan lebih burukstrncat()
adalah pengganti yang masuk akal untuk varian n-less.Sekali lagi orang mengulang, seperti mantra, pernyataan menggelikan bahwa versi "n" dari fungsi str adalah versi yang aman.
Jika itu yang dimaksudkan untuk mereka maka mereka akan selalu membatalkan string.
Versi "n" dari fungsi tersebut ditulis untuk digunakan dengan bidang panjang tetap (seperti entri direktori di sistem file awal) di mana terminator nul hanya diperlukan jika string tidak mengisi bidang. Ini juga alasan mengapa fungsi memiliki efek samping aneh yang tidak efisien jika hanya digunakan sebagai pengganti - ambil strncpy () misalnya:
Karena buffer yang dialokasikan untuk menangani nama file biasanya berukuran 4kbytes, hal ini dapat menyebabkan penurunan kinerja yang sangat besar.
Jika Anda menginginkan versi yang "seharusnya" aman, dapatkan - atau tulis sendiri - rutinitas strl Anda (strlcpy, strlcat dll) yang selalu nul mengakhiri string dan tidak memiliki efek samping. Harap dicatat bahwa ini tidak benar-benar aman karena mereka dapat memotong string secara diam-diam - ini jarang merupakan tindakan terbaik dalam program dunia nyata mana pun. Ada kalanya hal ini baik-baik saja tetapi ada juga banyak keadaan di mana hal itu dapat menyebabkan hasil bencana (misalnya mencetak resep medis).
sumber
strncpy()
, tapi salah tentangstrncat()
.strncat()
tidak dirancang untuk digunakan dengan bidang dengan panjang tetap - itu sebenarnya dirancang untuk menjadistrcat()
yang membatasi jumlah karakter yang digabungkan. Sangat mudah untuk menggunakan ini sebagai "amanstrcat()
" dengan melacak ruang yang tersisa di buffer saat melakukan beberapa penggabungan, dan bahkan lebih mudah menggunakannya sebagai "amanstrcpy()
" (dengan menyetel karakter pertama dari buffer tujuan ke'\0'
before menyebutnya).strncat()
selalu mengakhiri string tujuan, dan tidak menulis'\0'
s ekstra .strncat()
tidak selalu membatalkan tujuan, dan itu dirancang untuk digunakan dengan bidang dengan panjang tetap, keduanya salah.strncat()
akan berfungsi dengan baik terlepas dari panjang string sumber, sementarastrcat()
tidak. Masalahnya distrlcat()
sini adalah bahwa ini bukan fungsi C standar.Beberapa jawaban di sini menyarankan penggunaan
strncat()
overstrcat()
; Saya menyarankan bahwastrncat()
(danstrncpy()
) juga harus dihindari. Ini memiliki masalah yang membuatnya sulit untuk digunakan dengan benar dan menyebabkan bug:strncat()
terkait dengan (tetapi tidak persis sama - lihat poin ke-3) jumlah maksimum karakter yang dapat disalin ke tujuan daripada ukuran buffer tujuan. Ini membuatstrncat()
lebih sulit untuk digunakan daripada yang seharusnya, terutama jika beberapa item akan digabungkan ke tujuan.s1
adalahstrlen(s1)+n+1
" untuk panggilan yang terlihat sepertistrncat( s1, s2, n)
strncpy()
juga memiliki masalah yang dapat mengakibatkan bug yang Anda coba gunakan dengan cara yang intuitif - hal itu tidak menjamin bahwa tujuan tersebut dibatalkan. Untuk memastikan bahwa Anda harus memastikan Anda secara khusus menangani kasus sudut itu dengan meletakkan'\0'
sendiri di lokasi terakhir buffer (setidaknya dalam situasi tertentu).Saya menyarankan untuk menggunakan sesuatu seperti OpenBSD
strlcat()
danstrlcpy()
(meskipun saya tahu bahwa beberapa orang tidak menyukai fungsi tersebut; Saya yakin mereka jauh lebih mudah digunakan dengan aman daripadastrncat()
/strncpy()
).Inilah sedikit dari apa yang Todd Miller dan Theo de Raadt katakan tentang masalah dengan
strncat()
danstrncpy()
:Audit keamanan OpenBSD menemukan bahwa bug dengan fungsi ini "merajalela". Berbeda dengan
gets()
fungsi tersebut dapat digunakan dengan aman, tetapi dalam praktiknya ada banyak masalah karena antarmukanya membingungkan, tidak intuitif, dan sulit digunakan dengan benar. Saya tahu bahwa Microsoft juga telah melakukan analisis (meskipun saya tidak tahu berapa banyak data mereka yang mungkin telah mereka terbitkan), dan akibatnya telah melarang (atau setidaknya sangat tidak dianjurkan - 'larangan' mungkin tidak mutlak) penggunaanstrncat()
danstrncpy()
(di antara fungsi lainnya).Beberapa tautan dengan informasi lebih lanjut:
sumber
memmove()
. (Nah, Anda dapat menggunakanmemcpy()
dalam kasus normal ketika stringnya independen.)strncat()
selalu mengakhiri string tujuan.strncat()
. Namun, itu benarstrncpy()
, yang memiliki beberapa masalah lain.strncat()
adalah pengganti yang wajar untukstrcat()
, tetapistrncpy()
bukan pengganti yang wajar untukstrcpy()
.strncat()
tidak selalu batal. Saya membingungkan perilakustrncat()
danstrncpy()
sedikit (alasan lain mengapa mereka berfungsi untuk dihindari - mereka memiliki nama yang menyiratkan perilaku serupa, tetapi pada kenyataannya berperilaku berbeda dalam cara yang penting ...). Saya telah mengubah jawaban saya untuk mengoreksi ini serta menambahkan informasi tambahan.char str[N] = ""; strncat(str, "long string", sizeof(str));
buffer overflow jika N tidak cukup besar. Thestrncat()
Fungsi terlalu mudah untuk penyalahgunaan; itu tidak boleh digunakan. Jika Anda dapat menggunakanstrncat()
dengan aman, Anda dapat menggunakanmemmove()
ataumemcpy()
sebagai gantinya (dan itu akan lebih efisien).Fungsi pustaka standar yang tidak boleh digunakan:
setjmp.h
setjmp()
. Bersama-samalongjmp()
, fungsi-fungsi ini secara luas dikenal sebagai sangat berbahaya untuk digunakan: mereka mengarah pada pemrograman spaghetti, mereka datang dengan berbagai bentuk perilaku yang tidak ditentukan, mereka dapat menyebabkan efek samping yang tidak diinginkan dalam lingkungan program, seperti mempengaruhi nilai yang disimpan di stack. Referensi: MISRA-C: 2012 rule 21.4, CERT C MSC22-C .longjmp()
. Lihatsetjmp()
.stdio.h
gets()
. Fungsi tersebut telah dihapus dari bahasa C (sesuai C11), karena tidak aman sesuai desain. Fungsi tersebut sudah ditandai sebagai usang di C99. Gunakanfgets()
sebagai gantinya. Referensi: ISO 9899: 2011 K.3.5.4.1, lihat juga catatan 404.stdlib.h
atoi()
keluarga fungsi. Ini tidak memiliki penanganan kesalahan tetapi memanggil perilaku tidak ditentukan setiap kali terjadi kesalahan. Fungsi yang benar-benar berlebihan yang dapat diganti dengan fungsistrtol()
keluarga. Referensi: MISRA-C: 2012 aturan 21.7.string.h
strncat()
. Memiliki antarmuka yang canggung yang sering disalahgunakan. Ini sebagian besar merupakan fungsi yang tidak berguna. Lihat juga komentar untukstrncpy()
.strncpy()
. Tujuan dari fungsi ini tidak pernah menjadi versi yang lebih amanstrcpy()
. Tujuan utamanya adalah selalu untuk menangani format string kuno pada sistem Unix, dan yang dimasukkan ke dalam pustaka standar adalah kesalahan yang diketahui. Fungsi ini berbahaya karena dapat meninggalkan string tanpa penghentian null dan pemrogram diketahui sering salah menggunakannya. Referensi: Mengapa strlcpy dan strlcat dianggap tidak aman? .Fungsi pustaka standar yang harus digunakan dengan hati-hati:
assert.h
assert()
. Dilengkapi dengan overhead dan umumnya tidak boleh digunakan dalam kode produksi. Lebih baik menggunakan penanganan kesalahan khusus aplikasi yang menampilkan kesalahan tetapi tidak selalu menutup seluruh program.signal.h
signal()
. Referensi: MISRA-C: 2012 aturan 21.5, CERT C SIG32-C .stdarg.h
va_arg()
keluarga fungsi. Kehadiran fungsi variabel-panjang dalam program C hampir selalu merupakan indikasi desain program yang buruk. Harus dihindari kecuali Anda memiliki persyaratan yang sangat spesifik.stdio.h
Umumnya, seluruh pustaka ini tidak direkomendasikan untuk kode produksi , karena terdapat banyak kasus perilaku yang tidak terdefinisi dengan baik dan keamanan jenis yang buruk.
fflush()
. Sangat bagus untuk digunakan untuk aliran keluaran. Memanggil perilaku yang tidak ditentukan jika digunakan untuk aliran input.gets_s()
. Versi amangets()
termasuk dalam antarmuka pemeriksaan batas C11. Ini lebih disukai untuk digunakanfgets()
sebagai gantinya, sesuai rekomendasi standar C. Referensi: ISO 9899: 2011 K.3.5.4.1.printf()
keluarga fungsi. Fungsi sumber daya berat yang datang dengan banyak perilaku tidak terdefinisi dan jenis keamanan yang buruk.sprintf()
juga memiliki kerentanan. Fungsi ini harus dihindari dalam kode produksi. Referensi: MISRA-C: 2012 aturan 21.6.scanf()
keluarga fungsi. Lihat komentar tentangprintf()
. Juga, -scanf()
rentan terhadap buffer overruns jika tidak digunakan dengan benar.fgets()
lebih disukai digunakan jika memungkinkan. Referensi: CERT C INT05-C , MISRA-C: 2012 aturan 21.6.tmpfile()
keluarga fungsi. Hadir dengan berbagai masalah kerentanan. Referensi: CERT C FIO21-C .stdlib.h
malloc()
keluarga fungsi. Sangat bagus untuk digunakan dalam sistem yang dihosting, meskipun waspadalah terhadap masalah umum di C90 dan karena itu jangan berikan hasilnya . Themalloc()
keluarga fungsi tidak boleh digunakan dalam berdiri bebas aplikasi. Referensi: MISRA-C: 2012 aturan 21.3.Juga perhatikan itu
realloc()
berbahaya jika Anda menimpa penunjuk lama dengan hasilrealloc()
. Jika fungsinya gagal, Anda membuat kebocoran.system()
. Hadir dengan banyak overhead dan meskipun portabel, seringkali lebih baik menggunakan fungsi API khusus sistem sebagai gantinya. Hadir dengan berbagai perilaku yang tidak terdefinisi dengan baik. Referensi: CERT C ENV33-C .string.h
strcat()
. Lihat komentar untukstrcpy()
.strcpy()
. Baik-baik saja untuk digunakan, kecuali ukuran data yang akan disalin tidak diketahui atau lebih besar dari buffer tujuan. Jika tidak dilakukan pemeriksaan ukuran data yang masuk, mungkin ada buffer overruns. Yang bukan karena kesalahanstrcpy()
dirinya sendiri, tetapi dari aplikasi panggilan - yangstrcpy()
tidak aman sebagian besar adalah mitos yang dibuat oleh Microsoft .strtok()
. Mengubah string pemanggil dan menggunakan variabel status internal, yang dapat membuatnya tidak aman di lingkungan multi-utas.sumber
static_assert()
di tempatassert()
, jika kondisi dapat diselesaikan pada waktu kompilasi. Juga,sprintf()
hampir selalu bisa digantisnprintf()
yang sedikit lebih aman.strtok()
dalam fungsi A berarti bahwa (a) fungsi tersebut tidak dapat memanggil fungsi lain yang juga digunakanstrtok()
saat A menggunakannya, dan (b) berarti bahwa tidak ada fungsi yang memanggil A dapat digunakanstrtok()
saat memanggil A. Dengan kata lain, menggunakanstrtok()
meracuni rantai panggilan; itu tidak dapat digunakan dengan aman dalam kode perpustakaan karena harus dokumen yang digunakanstrtok()
untuk mencegah pengguna lainstrtok()
memanggil kode perpustakaan.strncpy
adalah fungsi yang tepat untuk digunakan saat menulis buffer string dengan bantalan nol dengan data yang diambil dari string yang diakhiri nol atau buffer dengan bantalan nol yang ukurannya setidaknya sebesar tujuan. Buffer tanpa bantalan tidak terlalu umum, tapi juga tidak terlalu jelas.Beberapa orang akan mengklaim itu
strcpy
danstrcat
harus dihindari, demistrncpy
danstrncat
. Ini agak subjektif, menurut saya.Mereka harus dihindari saat berurusan dengan input pengguna - tidak diragukan lagi di sini.
Dalam kode "jauh" dari pengguna, ketika Anda hanya tahu buffernya cukup panjang,
strcpy
danstrcat
mungkin sedikit lebih efisien karena menghitungn
to pass ke sepupu mereka mungkin berlebihan.sumber
strlcat
danstrlcpy
, karena versi 'n' tidak menjamin penghentian NULL dari string tujuan.strncpy()
akan menulis menulis dengan tepatn
byte, menggunakan karakter nul jika perlu. Sebagai Dan, menggunakan versi aman adalah IMO pilihan terbaik.strncat()
mungkin sulit untuk digunakan dengan benar dan aman (dan harus dihindari) ada di topik.Menghindari
strtok
untuk program multithread karena tidak thread-safe.gets
karena dapat menyebabkan buffer overflowsumber
strtok()
berjalan sedikit di luar keamanan utas - itu tidak aman bahkan dalam program utas tunggal kecuali Anda tahu pasti bahwa tidak ada fungsi yang mungkin dipanggil kode Anda saat menggunakanstrtok()
tidak juga menggunakannya (atau mereka akan mengacaukanstrtok()
status benar dari bawah Anda). Faktanya, sebagian besar kompiler yang menargetkan platform multi-threaded menanganistrtok()
potensi masalah sejauh thread berjalan dengan menggunakan penyimpanan lokal thread untukstrtok()
data statis. Tapi itu masih tidak memperbaiki masalah fungsi lain yang menggunakannya saat Anda berada (di utas yang sama).strtok()
adalah ia menyimpan satu buffer dengan tepat untuk bekerja, jadi sebagian besar penggantian yang baik memerlukan menjaga nilai buffer di sekitar dan meneruskannya.strcspn
melakukan sebagian besar dari yang Anda butuhkan - temukan pemisah token berikutnya. Anda dapat menerapkan kembali varian yang warasstrtok
dengannya.Mungkin perlu ditambahkan lagi yang
strncpy()
bukan pengganti tujuan umum untukstrcpy()
yang mungkin disarankan oleh namanya. Ini dirancang untuk bidang dengan panjang tetap yang tidak memerlukan nul-terminator (ini pada awalnya dirancang untuk digunakan dengan entri direktori UNIX, tetapi dapat berguna untuk hal-hal seperti bidang kunci enkripsi).Namun, mudah digunakan
strncat()
sebagai pengganti untukstrcpy()
:if (dest_size > 0) { dest[0] = '\0'; strncat(dest, source, dest_size - 1); }
(
if
Tes jelas dapat dibatalkan dalam kasus umum, di mana Anda tahu itudest_size
pasti bukan nol).sumber
Lihat juga daftar API terlarang Microsoft . Ini adalah API (termasuk banyak yang sudah terdaftar di sini) yang dilarang dari kode Microsoft karena sering disalahgunakan dan menyebabkan masalah keamanan.
Anda mungkin tidak setuju dengan semuanya, tetapi semuanya layak dipertimbangkan. Mereka menambahkan API ke daftar ketika penyalahgunaannya menyebabkan sejumlah bug keamanan.
sumber
Hampir semua fungsi yang berhubungan dengan string yang dihentikan NUL berpotensi tidak aman. Jika Anda menerima data dari dunia luar dan memanipulasinya melalui fungsi str * () maka Anda menyiapkan diri Anda untuk bencana
sumber
Jangan lupa tentang sprintf - ini adalah penyebab dari banyak masalah. Ini benar karena alternatifnya, snprintf terkadang memiliki implementasi berbeda yang dapat membuat kode Anda tidak dapat dibawa.
linux: http://linux.die.net/man/3/snprintf
windows: http://msdn.microsoft.com/en-us/library/2ts7cx93%28VS.71%29.aspx
Dalam kasus 1 (linux) nilai yang dikembalikan adalah jumlah data yang dibutuhkan untuk menyimpan seluruh buffer (jika lebih kecil dari ukuran buffer yang diberikan maka keluarannya dipotong)
Dalam kasus 2 (windows) nilai yang dikembalikan adalah angka negatif jika output terpotong.
Umumnya, Anda harus menghindari fungsi yang bukan:
buffer overflow safe (banyak fungsi telah disebutkan di sini)
benang aman / tidak reentrant (strtok misalnya)
Dalam manual setiap fungsi Anda harus mencari kata kunci seperti: aman, sinkron, asinkron, utas, buffer, bug
sumber
_sprintf()
dibuat oleh Microsoft sebelum standarsnprintf()
tiba, IIRC. ´StringCbPrintf () ´ sangat miripsnprintf()
.sprintf
entah bagaimana dengan aman dalam beberapa kasus:sprintf(buffer,"%10s",input);
membatasi nb disalin byte ke 10 (jikabuffer
inichar buffer[11]
itu aman bahkan jika data mungkin angin terpotong.Sangat sulit untuk digunakan
scanf
dengan aman. Penggunaan yang baik dariscanf
dapat menghindari buffer overflows, tetapi Anda masih rentan terhadap perilaku tidak terdefinisi saat membaca angka yang tidak sesuai dengan jenis yang diminta. Dalam kebanyakan kasus,fgets
diikuti oleh self-parsing (menggunakansscanf
,strchr
, dll) adalah pilihan yang lebih baik.Tapi saya tidak akan mengatakan "hindari
scanf
sepanjang waktu".scanf
memiliki kegunaannya. Sebagai contoh, katakanlah Anda ingin membaca input pengguna dalamchar
array yang panjangnya 10 byte. Anda ingin menghapus baris baru, jika ada. Jika pengguna memasukkan lebih dari 9 karakter sebelum baris baru, Anda ingin menyimpan 9 karakter pertama dalam buffer dan membuang semuanya hingga baris baru berikutnya. Anda dapat melakukan:char buf[10]; scanf("%9[^\n]%*[^\n]", buf)); getchar();
Setelah Anda terbiasa dengan idiom ini, itu lebih pendek dan dalam beberapa hal lebih bersih daripada:
char buf[10]; if (fgets(buf, sizeof buf, stdin) != NULL) { char *nl; if ((nl = strrchr(buf, '\n')) == NULL) { int c; while ((c = getchar()) != EOF && c != '\n') { ; } } else { *nl = 0; } }
sumber
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 }; /* The compiler NUL-fills the rest */
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) { /* Do some error-handling */ } /* If using MFC, you need if(... < 0), instead */
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.
sumber
atoi tidak aman untuk benang. Saya menggunakan strtol sebagai gantinya, sesuai rekomendasi dari halaman manual.
sumber
strtol()
menjadi thread-safe danatoi()
tidak akan aman.man atoi
(meskipun demikian).