alloca()
mengalokasikan memori pada stack daripada pada heap, seperti pada kasus malloc()
. Jadi, ketika saya kembali dari rutinitas, memori itu dibebaskan. Jadi, sebenarnya ini memecahkan masalah saya membebaskan memori yang dialokasikan secara dinamis. Membebaskan memori yang dialokasikan melalui malloc()
adalah sakit kepala utama dan jika entah bagaimana terlewatkan mengarah ke semua jenis masalah memori.
Mengapa penggunaan alloca()
berkecil hati meskipun fitur di atas?
free
(yang jelas merupakan keuntungan), ketidakmampuan untuk menyelaraskannya (jelas tumpukan alokasi jauh lebih berat) dan lain-lain. Satu-satunya alasan untuk menghindarialloca
adalah untuk ukuran besar. Artinya, membuang banyak memori stack bukanlah ide yang baik, ditambah Anda memiliki kemungkinan stack overflow. Jika ini masalahnya - pertimbangkan untuk menggunakanmalloca
/freea
alloca
adalah bahwa tumpukan tidak dapat terfragmentasi seperti tumpukan. Ini bisa terbukti berguna untuk aplikasi gaya run-forever yang sulit real-time, atau bahkan aplikasi yang kritis terhadap keselamatan, karena WCRU kemudian dapat dianalisis secara statis tanpa menggunakan kolam memori khusus dengan serangkaian masalah mereka sendiri (tidak ada temporal locality, sumber daya sub-optimal menggunakan).Jawaban:
Jawabannya ada di sana di
man
halaman (setidaknya di Linux ):Yang tidak mengatakan itu tidak boleh digunakan. Salah satu proyek OSS yang saya kerjakan menggunakannya secara luas, dan selama Anda tidak menyalahgunakannya (
alloca
nilai-nilai yang sangat besar), tidak apa-apa. Setelah Anda melewati tanda "beberapa ratus byte", sekarang saatnya untuk menggunakanmalloc
dan berteman. Anda mungkin masih mendapatkan kegagalan alokasi, tetapi setidaknya Anda akan memiliki beberapa indikasi kegagalan alih-alih hanya meniup tumpukan.sumber
alloca()
tidak memiliki ketakutan yang sama terhadap array atau rekursi lokal (pada kenyataannya banyak orang yang akan berteriakalloca()
akan memuji rekursi karena "terlihat elegan") . Saya setuju dengan saran Shaun ("Alokasi () baik untuk alokasi kecil") tetapi saya tidak setuju dengan pola pikir yang menetapkan Alokasi () sebagai kejahatan unik di antara 3 - mereka sama-sama berbahaya!Salah satu bug paling berkesan yang saya miliki adalah hubungannya dengan fungsi inline yang digunakan
alloca
. Itu memanifestasikan dirinya sebagai stack overflow (karena mengalokasikan pada stack) pada titik-titik acak dari eksekusi program.Dalam file header:
Dalam file implementasi:
Jadi yang terjadi adalah
DoSomething
fungsi iniler kompiler dan semua alokasi stack terjadi di dalamProcess()
fungsi dan dengan demikian meledakkan stack. Dalam pembelaan saya (dan saya bukan orang yang menemukan masalah; Saya harus pergi dan menangis ke salah satu pengembang senior ketika saya tidak bisa memperbaikinya), itu tidak lurusalloca
, itu adalah salah satu dari konversi string ATL makro.Jadi pelajarannya adalah - jangan gunakan
alloca
dalam fungsi yang Anda pikir mungkin diuraikan.sumber
Pertanyaan lama tetapi tidak ada yang menyebutkan bahwa itu harus diganti dengan array panjang variabel.
dari pada
Itu di C99 standar dan ada sebagai ekstensi kompiler di banyak kompiler.
sumber
Alokasi () sangat berguna jika Anda tidak dapat menggunakan variabel lokal standar karena ukurannya perlu ditentukan saat runtime dan Anda benar - benar dapat menjamin bahwa pointer yang Anda dapatkan dari Alokasi () TIDAK akan pernah digunakan setelah fungsi ini kembali .
Anda bisa cukup aman jika Anda
Bahaya sebenarnya datang dari kemungkinan bahwa orang lain akan melanggar kondisi ini beberapa waktu kemudian. Dengan mengingat hal itu, sangat bagus untuk meneruskan buffer ke fungsi yang memformat teks ke dalamnya :)
sumber
alloca()
alokasikan memori yang bertahan hingga akhir fungsi. Ini berarti bahwa tampaknya tidak ada terjemahan langsung dan mudah ke VLA darif() { char *p; if (c) { /* compute x */ p = alloca(x); } else { p = 0; } /* use p */ }
. Jika Anda pikir mungkin untuk secara otomatis menerjemahkan penggunaanalloca
ke penggunaan VLA tetapi membutuhkan lebih dari komentar untuk menjelaskan caranya, saya dapat membuat ini menjadi pertanyaan.Seperti disebutkan dalam posting newsgroup ini , ada beberapa alasan mengapa menggunakan
alloca
bisa dianggap sulit dan berbahaya:alloca
.alloca
berbeda, sehingga portabilitas tidak dijamin bahkan di antara kompiler yang mendukungnya.sumber
alloca()
memerlukan register terpisah untuk memegang penunjuk tumpukan dan penunjuk bingkai. Pada CPU x86> = 386, penunjuk tumpukanESP
dapat digunakan untuk keduanya, membebaskanEBP
- kecuali jikaalloca()
digunakan.f(42, alloca(10), 43);
bisa macet karena kemungkinan bahwa penunjuk tumpukan disesuaikanalloca()
setelah setidaknya salah satu argumen didorong di atasnya.Satu masalah adalah itu bukan standar, meskipun didukung secara luas. Hal lain dianggap sama, saya selalu menggunakan fungsi standar daripada ekstensi kompiler umum.
sumber
Saya tidak melihat konsensus seperti itu. Banyak pro kuat; beberapa kontra:
while
ataufor
loop) atau dalam beberapa lingkup, memori menumpuk per iterasi / ruang lingkup dan tidak dirilis sampai fungsi keluar: ini kontras dengan variabel normal yang didefinisikan dalam lingkup struktur kontrol (misalnyafor {int i = 0; i < 2; ++i) { X }
akan menumpukalloca
memori yang diminta pada X, tetapi memori untuk array berukuran tetap akan didaur ulang per iterasi).inline
berfungsi yang memanggilalloca
, tetapi jika Anda memaksa mereka makaalloca
akan terjadi dalam konteks pemanggil (yaitu tumpukan tidak akan dirilis sampai pemanggil kembali)alloca
beralih dari fitur non-portable / hack ke ekstensi standar, tetapi beberapa persepsi negatif mungkin bertahanmalloc
kontrol eksplisitmalloc
pemikiran mendorong tentang deallokasi - jika itu dikelola melalui fungsi wrapper (misalnyaWonderfulObject_DestructorFree(ptr)
), maka fungsi tersebut menyediakan titik untuk implementasi operasi pembersihan (seperti menutup deskriptor file, membebaskan pointer internal atau melakukan logging) tanpa perubahan eksplisit ke klien kode: kadang model yang bagus untuk diadopsi secara konsistenWonderfulObject* p = WonderfulObject_AllocConstructor();
- itu mungkin ketika "constructor" adalah fungsimalloc
memori yang dikembalikan (karena memori tetap dialokasikan setelah fungsi mengembalikan nilai untuk disimpan dalamp
), tetapi tidak jika "konstruktor" menggunakanalloca
WonderfulObject_AllocConstructor
bisa mencapai ini, tetapi "makro jahat" di mana mereka dapat saling bertentangan dan kode non-makro dan membuat substitusi yang tidak diinginkan dan akibatnya sulit didiagnosis masalahfree
operasi yang hilang dapat dideteksi oleh ValGrind, Purify dll. tetapi panggilan "destruktor" yang hilang tidak dapat dideteksi sama sekali - satu manfaat yang sangat lemah dalam hal penegakan penggunaan yang dimaksudkan; beberapaalloca()
implementasi (seperti GCC) menggunakan makro inlinealloca()
, jadi substitusi runtime dari perpustakaan diagnostik penggunaan memori tidak mungkin seperti itu untukmalloc
/realloc
/free
(misalnya pagar listrik)Saya tahu pertanyaan ini ditandai C, tetapi sebagai seorang programmer C ++ saya pikir saya akan menggunakan C ++ untuk menggambarkan utilitas potensial dari
alloca
: kode di bawah ini (dan di sini di ideone ) menciptakan vektor pelacakan jenis polimorfik berukuran berbeda yang dialokasikan stack (dengan seumur hidup terikat dengan fungsi return) daripada tumpukan dialokasikan.sumber
Semua jawaban lainnya benar. Namun, jika hal yang ingin Anda alokasikan menggunakan
alloca()
cukup kecil, saya pikir itu adalah teknik bagus yang lebih cepat dan lebih nyaman daripada menggunakanmalloc()
atau sebaliknya.Dengan kata lain,
alloca( 0x00ffffff )
itu berbahaya dan cenderung menyebabkan meluap, persis sebanyak apachar hugeArray[ 0x00ffffff ];
adanya. Berhati-hatilah dan masuk akal dan Anda akan baik-baik saja.sumber
Banyak jawaban menarik untuk pertanyaan "lama" ini, bahkan beberapa jawaban yang relatif baru, tetapi saya tidak menemukan yang menyebutkan ini ....
Saya menemukan kutipan itu di .... OK, saya membuat kutipan itu. Tapi sungguh, pikirkan tentang itu ....
@j_random_hacker sangat benar dalam komentarnya di bawah jawaban lain: Menghindari penggunaan yang
alloca()
mendukung array lokal berukuran besar tidak membuat program Anda lebih aman dari stack overflow (kecuali jika kompiler Anda sudah cukup tua untuk memungkinkan inlining fungsi yang digunakanalloca()
dalam hal ini Anda harus tingkatkan, atau kecuali jika Anda menggunakanalloca()
loop dalam, dalam hal ini Anda harus ... tidak menggunakanalloca()
loop dalam).Saya telah bekerja di lingkungan desktop / server dan sistem embedded. Banyak sistem tertanam tidak menggunakan tumpukan sama sekali (mereka bahkan tidak menautkan dukungan untuk itu), untuk alasan yang mencakup persepsi bahwa memori yang dialokasikan secara dinamis adalah jahat karena risiko kebocoran memori pada aplikasi yang tidak pernah pernah reboot selama bertahun-tahun pada suatu waktu, atau pembenaran yang lebih masuk akal bahwa memori dinamis berbahaya karena tidak dapat diketahui secara pasti bahwa suatu aplikasi tidak akan pernah memecah tumpukannya ke titik kehabisan memori palsu. Jadi programmer yang tertanam dibiarkan dengan beberapa alternatif.
alloca()
(atau VLA) mungkin alat yang tepat untuk pekerjaan itu.Saya telah melihat waktu & waktu lagi di mana seorang programmer membuat buffer yang dialokasikan stack "cukup besar untuk menangani setiap kasus yang mungkin". Dalam pohon panggilan yang sangat bersarang, penggunaan berulang pola (anti -?) Mengarah ke penggunaan tumpukan berlebihan. (Bayangkan pohon panggilan sedalam 20 level, di mana pada setiap level karena alasan yang berbeda, fungsinya secara membabi buta mengalokasikan buffer 1024 byte "hanya untuk aman" ketika umumnya hanya akan menggunakan 16 atau kurang dari itu, dan hanya di sangat kasus yang jarang dapat menggunakan lebih banyak.) Alternatif adalah menggunakan
alloca()
atau VLA dan hanya mengalokasikan ruang stack sebanyak yang dibutuhkan fungsi Anda, untuk menghindari membebani stack secara tidak perlu. Mudah-mudahan ketika satu fungsi di pohon panggilan membutuhkan alokasi yang lebih besar dari normal, yang lain di pohon panggilan masih menggunakan alokasi kecil normal mereka, dan keseluruhan penggunaan tumpukan aplikasi secara signifikan lebih kecil daripada jika setiap fungsi secara membabi buta mengalokasikan buffer lokal .Tetapi jika Anda memilih untuk menggunakan
alloca()
...Berdasarkan jawaban lain pada halaman ini, tampaknya VLA harus aman (mereka tidak menambah alokasi tumpukan jika dipanggil dari dalam satu loop), tetapi jika Anda menggunakan
alloca()
, berhati-hatilah untuk tidak menggunakannya di dalam loop, dan buatlah Pastikan fungsi Anda tidak dapat digarisbawahi jika ada kemungkinan ia dipanggil dalam loop fungsi lain.sumber
alloca()
benar, tetapi hal yang sama dapat dikatakan kebocoran memorimalloc()
(mengapa tidak menggunakan GC? Orang mungkin berpendapat).alloca()
bila digunakan dengan hati-hati bisa sangat berguna untuk mengurangi ukuran tumpukan.Semua orang sudah menunjukkan hal besar yang berpotensi perilaku tidak terdefinisi dari stack overflow, tetapi saya harus menyebutkan bahwa lingkungan Windows memiliki mekanisme yang bagus untuk menangkap ini menggunakan pengecualian terstruktur (SEH) dan halaman penjaga. Karena tumpukan hanya tumbuh sesuai kebutuhan, halaman penjaga ini berada di area yang tidak terisi. Jika Anda mengalokasikan ke dalamnya (dengan meluap tumpukan) pengecualian dilemparkan.
Anda dapat menangkap pengecualian SEH ini dan memanggil _resetstkoflw untuk mengatur ulang tumpukan dan melanjutkan dengan cara merry. Itu tidak ideal tapi ini mekanisme lain untuk setidaknya tahu ada yang tidak beres ketika barang itu mengenai kipas. * nix mungkin memiliki sesuatu yang mirip yang tidak saya sadari.
Saya sarankan membatasi ukuran alokasi maksimum Anda dengan membungkus alokasi dan melacaknya secara internal. Jika Anda benar-benar hardcore tentang hal itu, Anda bisa melempar beberapa ruang lingkup penjaga di bagian atas fungsi Anda untuk melacak alokasi alokasi dalam lingkup fungsi dan kewarasan memeriksa ini terhadap jumlah maksimum yang diizinkan untuk proyek Anda.
Selain itu, selain tidak memungkinkan alokasi memori tidak menyebabkan fragmentasi memori yang cukup penting. Saya tidak berpikir alokasi adalah praktik yang buruk jika Anda menggunakannya secara cerdas, yang pada dasarnya berlaku untuk semuanya. :-)
sumber
alloca()
dapat menuntut banyak ruang, sehingga stackpointer mendarat di heap. Dengan itu, seorang penyerang yang dapat mengontrol ukuranalloca()
dan data yang masuk ke buffer itu dapat menimpa tumpukan (yang sangat buruk).Alokasi () bagus dan efisien ... tetapi juga sangat rusak.
Dalam kebanyakan kasus, Anda dapat menggantinya menggunakan variabel lokal dan ukuran majorant. Jika digunakan untuk objek besar, meletakkannya di tumpukan biasanya merupakan ide yang lebih aman.
Jika Anda benar-benar membutuhkannya C Anda dapat menggunakan VLA (tidak ada vla di C ++, terlalu buruk). Mereka jauh lebih baik daripada alokasi () mengenai perilaku dan konsistensi ruang lingkup. Seperti yang saya lihat, VLA adalah semacam alokasi () yang dibuat benar.
Tentu saja struktur lokal atau array menggunakan majorant dari ruang yang dibutuhkan masih lebih baik, dan jika Anda tidak memiliki alokasi heap majorant menggunakan plain malloc () mungkin waras. Saya tidak melihat kasus penggunaan yang waras di mana Anda benar-benar membutuhkan alokasi () atau VLA.
sumber
alloca
tidak membuat nama, hanya rentang memori, yang memiliki masa pakai .alloca
ataumalloc
ataufree
langsung. Saya mengatakan hal-hal seperti{stack|heap}_alloc_{bytes,items,struct,varstruct}
dan{stack|heap}_dealloc
. Jadi,heap_dealloc
panggil sajafree
danstack_dealloc
jangan-pilih. Dengan cara ini, alokasi tumpukan dapat dengan mudah diturunkan ke tumpukan alokasi, dan niat lebih jelas juga.Inilah alasannya:
Bukan berarti siapa pun akan menulis kode ini, tetapi argumen ukuran yang Anda sampaikan
alloca
hampir pasti berasal dari semacam input, yang bisa bertujuan jahat untuk membuat program Anda menjadialloca
sesuatu yang besar seperti itu. Lagi pula, jika ukurannya tidak berdasarkan input atau tidak memiliki kemungkinan besar, mengapa Anda tidak mendeklarasikan buffer lokal berukuran kecil dan berukuran tetap?Hampir semua kode menggunakan
alloca
dan / atau C99 vlas memiliki bug serius yang akan menyebabkan crash (jika Anda beruntung) atau kompromi privilege (jika Anda tidak seberuntung itu).sumber
alloca
. Anda mengatakan bahwa hampir semua kode yang menggunakannya memiliki bug, tapi saya berencana menggunakannya; Saya biasanya mengabaikan klaim seperti itu, tetapi datang dari Anda saya tidak akan. Saya sedang menulis mesin virtual dan saya ingin mengalokasikan variabel yang tidak luput dari fungsi pada stack, bukan secara dinamis, karena percepatan yang sangat besar. pendekatan yang memiliki karakteristik kinerja yang sama? Saya tahu saya bisa dekat dengan kolam memori, tapi itu masih tidak murah. Apa yang akan Anda lakukan?*0 = 9;
LUAR BIASA !!! Saya kira saya seharusnya tidak pernah menggunakan pointer (atau setidaknya dereferensi mereka). Err, tunggu. Saya dapat menguji untuk melihat apakah itu nol. Hmm. Saya kira saya juga dapat menguji ukuran memori yang ingin saya alokasikan melaluialloca
. Pria aneh Aneh.*0=9;
tidak valid C. Sedangkan untuk menguji ukuran yang Anda lolosalloca
, mengujinya terhadap apa? Tidak ada cara untuk mengetahui batasnya, dan jika Anda hanya akan mengujinya terhadap ukuran kecil yang diketahui aman (misalnya 8k) Anda mungkin juga hanya menggunakan array ukuran tetap pada tumpukan.small_constant * log(user_input)
maka kita mungkin memiliki cukup memori.Saya tidak berpikir ada yang menyebutkan ini: Penggunaan alokasi dalam suatu fungsi akan menghalangi atau menonaktifkan beberapa optimasi yang dapat diterapkan dalam fungsi, karena kompiler tidak dapat mengetahui ukuran bingkai tumpukan fungsi.
Sebagai contoh, optimasi umum oleh kompiler C adalah untuk menghilangkan penggunaan frame pointer dalam suatu fungsi, akses frame dibuat relatif terhadap stack pointer sebagai gantinya; jadi ada satu register lagi untuk penggunaan umum. Tetapi jika alokasi disebut di dalam fungsi, perbedaan antara sp dan fp tidak akan diketahui untuk bagian dari fungsi, sehingga optimasi ini tidak dapat dilakukan.
Mengingat kelangkaan penggunaannya, dan statusnya yang teduh sebagai fungsi standar, perancang kompiler sangat mungkin menonaktifkan pengoptimalan apa pun yang dapat menyebabkan masalah dengan pengalokasian, jika perlu lebih dari sedikit upaya untuk membuatnya berfungsi dengan pengalokasian.
UPDATE: Karena array lokal panjang variabel telah ditambahkan ke C, dan karena ini menyajikan masalah pembuatan kode yang sangat mirip dengan kompiler sebagai alokasi, saya melihat bahwa 'kelangkaan penggunaan dan status teduh' tidak berlaku untuk mekanisme yang mendasarinya; tapi saya masih akan curiga bahwa penggunaan salah satu alokasi atau VLA cenderung kompromi pembuatan kode dalam fungsi yang menggunakannya. Saya akan menerima umpan balik dari desainer kompiler.
sumber
Satu perangkap dengan
alloca
itu yanglongjmp
memundurkannya.Artinya, jika Anda menyimpan konteks dengan
setjmp
, makaalloca
beberapa memori, makalongjmp
ke konteksnya, Anda mungkin kehilanganalloca
memori. Penunjuk tumpukan kembali ke tempatnya semula sehingga memori tidak lagi dicadangkan; jika Anda memanggil suatu fungsi atau melakukan yang lainalloca
, Anda akan mengalahkan yang aslialloca
.Untuk memperjelas, apa yang saya maksudkan secara khusus di sini adalah situasi di mana
longjmp
tidak kembali dari fungsi di manaalloca
terjadi! Sebaliknya, fungsi menyimpan konteks dengansetjmp
; kemudian mengalokasikan memori denganalloca
dan akhirnya longjmp terjadi pada konteks itu.alloca
Memori fungsi itu tidak semuanya dibebaskan; hanya semua memori yang dialokasikan sejaksetjmp
. Tentu saja, saya berbicara tentang perilaku yang diamati; tidak ada persyaratan seperti itu yang didokumentasikanalloca
yang saya tahu.Fokus dalam dokumentasi biasanya pada konsep bahwa
alloca
memori dikaitkan dengan aktivasi fungsi , bukan dengan blok apa pun; bahwa banyak pemanggilanalloca
hanya mengambil lebih banyak memori tumpukan yang semuanya dilepaskan ketika fungsi berakhir. Tidak begitu; memori sebenarnya terkait dengan konteks prosedur. Ketika konteksnya dipulihkanlongjmp
, demikian jugaalloca
keadaan sebelumnya . Ini adalah konsekuensi dari register penunjuk tumpukan itu sendiri yang digunakan untuk alokasi, dan juga (tentu saja) disimpan dan dipulihkan dijmp_buf
.Kebetulan, ini, jika bekerja seperti itu, menyediakan mekanisme yang masuk akal untuk secara sengaja membebaskan memori yang dialokasikan bersama
alloca
.Saya telah menemukan ini sebagai penyebab utama bug.
sumber
longjmp
kembali dan membuatnya sehingga program lupa tentang semua yang terjadi di stack: semua variabel, pemanggilan fungsi dll. Danalloca
seperti array pada stack, jadi diharapkan mereka akan musnah seperti yang lainnya di stack.man alloca
memberikan kalimat berikut: "Karena ruang yang dialokasikan oleh dialokasikan () dialokasikan dalam bingkai tumpukan, ruang itu secara otomatis dibebaskan jika fungsi kembali dilompati oleh panggilan ke longjmp (3) atau siglongjmp (3).". Jadi didokumentasikan bahwa memori yang dialokasikan denganalloca
akan musnah setelah alongjmp
.longjmp
. Fungsi target belum kembali. Itu telah dilakukansetjmp
,alloca
dan kemudianlongjmp
. Thelongjmp
dapat memundurkanalloca
kembali negara untuk apa itu padasetjmp
waktu. Dengan kata lain, pointer yang dipindahkan olehalloca
menderita masalah yang sama dengan variabel lokal yang belum ditandaivolatile
!setjmp
kemudianalloca
, dan kemudianlongjmp
, itu normal yangalloca
akan mundur. Intinyalongjmp
adalah untuk kembali ke keadaan yang telah disimpansetjmp
!Sebuah tempat
alloca()
yang sangat berbahaya daripadamalloc()
kernel - kernel dari sistem operasi tipikal memiliki ruang stack berukuran tetap yang dikodekan ke dalam salah satu header-nya; itu tidak sefleksibel tumpukan aplikasi. Melakukan panggilan kealloca()
dengan ukuran yang tidak beralasan dapat menyebabkan kernel mogok. Kompiler tertentu memperingatkan penggunaanalloca()
(dan bahkan VLA dalam hal ini) di bawah opsi-opsi tertentu yang harus dinyalakan saat menyusun kode kernel - di sini, lebih baik untuk mengalokasikan memori di heap yang tidak diperbaiki oleh batas hard-coded.sumber
alloca()
tidak lebih berbahaya daripada diint foo[bar];
manabar
bilangan bulat sembarang.Jika Anda secara tidak sengaja menulis di luar blok yang dialokasikan dengan
alloca
(karena buffer overflow misalnya), maka Anda akan menimpa alamat kembali fungsi Anda, karena yang itu terletak "di atas" pada tumpukan, yaitu setelah blok yang dialokasikan.Konsekuensi dari ini adalah dua kali lipat:
Program akan crash secara spektakuler dan tidak mungkin untuk mengetahui mengapa atau di mana crash (stack kemungkinan besar akan lepas ke alamat acak karena frame pointer yang ditimpa).
Itu membuat buffer overflow berkali-kali lebih berbahaya, karena pengguna jahat dapat membuat muatan khusus yang akan diletakkan di tumpukan dan karenanya dapat berakhir dieksekusi.
Sebaliknya, jika Anda menulis di luar blok di heap Anda "hanya" mendapatkan korupsi tumpukan. Program ini mungkin akan berhenti secara tak terduga tetapi akan melepaskan tumpukan dengan benar, sehingga mengurangi kemungkinan eksekusi kode berbahaya.
sumber
alloca
.alloca
dibandingkan denganmalloc
(sehingga tidak buffer berukuran tetap pada stack).Sayangnya yang benar-benar luar biasa
alloca()
hilang dari tcc yang hampir luar biasa. Gcc memang punyaalloca()
.Itu menabur benih kehancurannya sendiri. Dengan pengembalian sebagai destruktor.
Seperti
malloc()
itu mengembalikan pointer tidak valid pada gagal yang akan segfault pada sistem modern dengan MMU (dan mudah-mudahan restart yang tanpa).Tidak seperti variabel otomatis, Anda dapat menentukan ukuran saat dijalankan.
Ini bekerja dengan baik dengan rekursi. Anda dapat menggunakan variabel statis untuk mencapai sesuatu yang mirip dengan rekursi ekor dan menggunakan hanya beberapa yang lain meneruskan info ke setiap iterasi.
Jika Anda mendorong terlalu dalam, Anda dijamin segfault (jika Anda memiliki MMU).
Catatan yang
malloc()
menawarkan tidak lebih karena mengembalikan NULL (yang juga akan segfault jika ditugaskan) ketika sistem kehabisan memori. Yaitu yang dapat Anda lakukan adalah jaminan atau hanya mencoba menetapkannya dengan cara apa pun.Untuk menggunakan
malloc()
saya menggunakan global dan menetapkannya NULL. Jika pointer bukan NULL saya membebaskannya sebelum saya gunakanmalloc()
.Anda juga dapat menggunakan
realloc()
sebagai kasus umum jika ingin menyalin data yang ada. Anda perlu memeriksa pointer sebelum bekerja jika Anda akan menyalin atau menyatukan setelahrealloc()
.3.2.5.2 Keuntungan dari alokasi
sumber
Proses hanya memiliki jumlah ruang stack yang terbatas - jauh lebih sedikit daripada jumlah memori yang tersedia
malloc()
.Dengan menggunakan
alloca()
Anda secara dramatis meningkatkan peluang Anda untuk mendapatkan kesalahan Stack Overflow (jika Anda beruntung, atau crash yang tidak dapat dijelaskan jika Anda tidak).sumber
Tidak terlalu cantik, tetapi jika kinerja benar-benar penting, Anda dapat mengalokasikan beberapa ruang di stack.
Jika Anda sekarang sudah ukuran maksimum memori memblokir kebutuhan Anda dan Anda ingin terus memeriksa melimpah, Anda bisa melakukan sesuatu seperti:
sumber
Fungsi alokasi sangat bagus dan semua penentang hanya menyebarkan FUD.
Array dan parray adalah PERSIS sama dengan risiko yang sama PERSIS. Mengatakan satu lebih baik daripada yang lain adalah pilihan sintaksis, bukan pilihan teknis.
Adapun untuk memilih variabel tumpukan vs variabel tumpukan, ada banyak keuntungan untuk program yang berjalan lama menggunakan tumpukan lebih dari tumpukan untuk variabel dengan masa hidup in-scope. Anda menghindari tumpukan tumpukan dan Anda bisa menghindari menumbuhkan ruang proses Anda dengan ruang tumpukan yang tidak digunakan (tidak dapat digunakan). Anda tidak perlu membersihkannya. Anda dapat mengontrol alokasi tumpukan pada proses.
Kenapa ini buruk?
sumber
Sebenarnya, alokasi tidak dijamin untuk menggunakan tumpukan. Memang, implementasi alokasi gcc-2.95 mengalokasikan memori dari heap menggunakan malloc itu sendiri. Juga implementasi yang bermasalah, dapat menyebabkan kebocoran memori dan beberapa perilaku yang tidak terduga jika Anda menyebutnya di dalam blok dengan penggunaan goto lebih lanjut. Tidak, untuk mengatakan bahwa Anda seharusnya tidak pernah menggunakannya, tetapi beberapa kali mengalokasikan mengarah ke lebih banyak overhead daripada yang dikeluarkan darinya.
sumber
alloca
. Bagaimana itu bisa membersihkan memori ketikalongjmp
digunakan untuk meninggalkan frame yang melakukannyaalloca
? Kapan orang akan menggunakan gcc 2,95 hari ini?IMHO, alokasi dianggap praktik buruk karena semua orang takut melelahkan batas ukuran tumpukan.
Saya belajar banyak dengan membaca utas ini dan beberapa tautan lainnya:
Saya menggunakan dialokasikan terutama untuk membuat file C biasa saya dapat dikompilasi di msvc dan gcc tanpa perubahan, gaya C89, tidak ada #ifdef _MSC_VER, dll.
Terima kasih ! Utas ini membuat saya mendaftar ke situs ini :)
sumber
Menurut pendapat saya, alokasi (), jika tersedia, harus digunakan hanya dengan cara terbatas. Sangat mirip dengan penggunaan "goto", cukup banyak orang yang beralasan memiliki keengganan yang kuat tidak hanya untuk penggunaan, tetapi juga keberadaan, alokasi ().
Untuk penggunaan tertanam, di mana ukuran tumpukan diketahui dan batas dapat dikenakan melalui konvensi dan analisis pada ukuran alokasi, dan di mana kompiler tidak dapat ditingkatkan untuk mendukung C99 +, penggunaan alokasi () baik-baik saja, dan saya sudah diketahui menggunakannya.
Ketika tersedia, VLA mungkin memiliki beberapa keunggulan dibandingkan dengan alokasi (): Kompilator dapat menghasilkan pemeriksaan batas tumpukan yang akan menangkap akses di luar batas ketika akses gaya array digunakan (saya tidak tahu apakah ada kompiler yang melakukan ini, tetapi ia dapat dilakukan), dan analisis kode dapat menentukan apakah ekspresi akses array dibatasi dengan benar. Perhatikan bahwa, dalam beberapa lingkungan pemrograman, seperti otomotif, peralatan medis, dan avionik, analisis ini harus dilakukan bahkan untuk array ukuran tetap, baik otomatis (pada tumpukan) dan alokasi statis (global atau lokal).
Pada arsitektur yang menyimpan data dan mengembalikan alamat / frame pointer pada stack (dari apa yang saya ketahui, semuanya), setiap variabel yang dialokasikan stack dapat berbahaya karena alamat variabel dapat diambil, dan nilai input yang tidak dicentang mungkin mengizinkan segala macam kerusakan.
Portabilitas kurang menjadi perhatian di ruang tertanam, namun itu adalah argumen yang baik terhadap penggunaan alokasi () di luar keadaan yang dikendalikan dengan cermat.
Di luar ruang yang disematkan, saya telah menggunakan Alokasi () sebagian besar di dalam fungsi logging dan pemformatan untuk efisiensi, dan dalam pemindai leksikal non-rekursif, di mana struktur sementara (dialokasikan menggunakan Alokasi () dibuat selama Tokenisasi dan klasifikasi, kemudian terus-menerus objek (dialokasikan melalui malloc ()) diisi sebelum fungsi kembali.Penggunaan alokasi () untuk struktur sementara yang lebih kecil sangat mengurangi fragmentasi ketika objek persisten dialokasikan.
sumber
Sebagian besar jawaban di sini sebagian besar tidak tepat: ada alasan mengapa menggunakan
_alloca()
berpotensi lebih buruk daripada hanya menyimpan benda besar di tumpukan.Perbedaan utama antara penyimpanan otomatis dan
_alloca()
bahwa yang terakhir menderita masalah (serius) tambahan: blok yang dialokasikan tidak dikontrol oleh kompiler , jadi tidak ada cara bagi kompiler untuk mengoptimalkan atau mendaur ulangnya.Membandingkan:
dengan:
Masalah dengan yang terakhir harus jelas.
sumber
alloca
(ya, saya katakan VLA, karenaalloca
lebih dari sekadar pencipta array ukuran statis)?Saya tidak berpikir bahwa ada orang yang menyebutkan ini, tetapi mengalokasikan juga memiliki beberapa masalah keamanan yang serius belum tentu hadir dengan malloc (meskipun masalah ini juga muncul dengan susunan array berbasis, dinamis atau tidak). Karena memori dialokasikan pada stack, buffer overflows / underflow memiliki konsekuensi yang jauh lebih serius daripada hanya dengan malloc.
Secara khusus, alamat pengirim untuk suatu fungsi disimpan pada stack. Jika nilai ini rusak, kode Anda dapat dibuat untuk pergi ke wilayah memori yang dapat dieksekusi. Compiler berusaha keras untuk membuat ini sulit (khususnya dengan mengacak tata letak alamat). Namun, ini jelas lebih buruk dari sekadar stack overflow karena kasus terbaik adalah SEGFAULT jika nilai pengembalian rusak, tetapi juga bisa mulai mengeksekusi sepotong memori acak atau dalam kasus terburuk beberapa wilayah memori yang membahayakan keamanan program Anda .
sumber