Katakanlah saya memiliki array C karakter char buf[15]
. Say variable int set_me = 0
menyimpan datanya di lokasi memori langsung setelahnya char buf[15]
. Jika saya dipenuhi buf
dengan string "aaabbbcccdddeee\xef\xbe\xad\xde"
, apakah set_me
tipe data akan berubah dari integer ke array karakter?
8
Jawaban:
Tidak.
"Tipe data" dari suatu variabel hanya relevan dalam kode sumber (dan itupun hanya dalam beberapa bahasa). Ini memberitahu kompiler bagaimana memperlakukan variabel.
Tipe data tingkat tinggi ini tidak ada dalam kode yang dikompilasi (asli). Mereka dapat mempengaruhi instruksi apa yang dihasilkan oleh kompiler, tetapi instruksi itu sendiri tidak peduli jika data tersebut mewakili karakter atau angka.
Variabel tidak ada di perangkat keras. Di perangkat keras, Anda memiliki lokasi memori dan instruksi yang beroperasi di sana.
Variabel dapat dilihat sebagai tampilan data di lokasi memori - jika Anda menyipitkan mata dan melihat memori yang sama sedikit berbeda (variabel berbeda dengan tipe berbeda merujuk ke lokasi yang sama), nilai biner yang sama dapat memiliki arti yang berbeda .
Sebagai contoh, byte 0x41 dapat diartikan sebagai karakter yang dikodekan oleh UTF-8
A
. Bisa juga diartikan sebagai integer byte tunggal65
. Bisa juga diartikan sebagai satu byte dalam integer multi-byte atau angka floating point, atau satu byte dalam pengkodean karakter multi-byte. Itu bisa berupa bitset0b1000001
. Semua dari byte yang sama di lokasi memori yang sama. Dalam bahasa C, Anda dapat melihat efek ini dengan melakukan casting ke tipe yang berbeda ini.Ketika Anda memiliki "buffer overflow", Anda melakukan sesuatu di luar batas yang mungkin diharapkan oleh kompiler atau bahasa Anda. Tetapi, sejauh menyangkut perangkat keras 1 , Anda menulis byte (baik tunggal atau ganda) ke lokasi memori. Lokasi memori tidak memiliki "tipe". Bahkan, perangkat keras bahkan tidak tahu bahwa set byte tertentu membuat array atau buffer dalam kode Anda.
Di mana pun Anda selanjutnya mengakses lokasi memori dalam kode Anda, instruksi akan berjalan seperti yang didefinisikan sebelumnya. misalnya jika mereka mengharapkan nomor di sana, mereka akan bertindak berdasarkan byte data apa pun seolah-olah mereka nomor.
Untuk menggunakan contoh Anda, anggap Anda
int
adalah integer 4-byte (32-bit) yang sudah ditandatangani:Anda dapat melihat bahwa
int
lokasi memori sekarang berisi0xEFBEADDE
, dengan asumsi sistem big-endian 2 . Ini adalah int 32-bit yang ditandatangani-272716322
. Sekarang, jika Anda mengartikan memori yang sama dengan int (uint
) yang tidak ditandatangani , itu akan menjadi4022250974
sebaliknya. Untuk data yang persis sama dalam memori, artinya sepenuhnya tergantung pada bagaimana Anda melihatnya.1 Ada beberapa mekanisme yang mencegah Anda dari menulis ke wilayah memori yang dilindungi, dan akan merusak program Anda jika Anda berupaya melakukannya.
2 x86 sebenarnya adalah little-endian, yang berarti Anda mengartikan byte yang membentuk nilai lebih besar ke belakang. Jadi pada x86 Anda malah harus
0xDEADBEEF
, memberi yang ditandatangani-559038737
atau tidak3735928559
.sumber
0xdeadbeef
, pada arsitektur x86, akan memakan lebih sedikit ruang dalam memori dibandingkan dengan desimalnya ,3735928559
?0xDEADBEEF
disimpan dalam memori sebagai0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46
.0xEFBEADDE
. Mungkin menulis ulang sedikit. Kalau tidak, ini adalah jawaban yang luar biasa - Saya terutama menyukai analogi "tampilan" dan ide "menyipitkan mata" :)Dari perspektif C, jawabannya adalah "Siapa yang tahu? Ini Perilaku Tidak Terdefinisi".
Jenis adalah konsep C, bukan perangkat keras. Tetapi aturan C tidak berlaku jika program Anda memiliki Perilaku Tidak Terdefinisi, itulah arti harfiah dari Perilaku Tidak Terdefinisi dalam standar C. Dan buffer overflow adalah salah satu bentuknya.
Saya awalnya menulis "aturan C tidak berlaku lagi", tetapi pada kenyataannya Perilaku Tidak Terdefinisi bersifat retroaktif. Aturan C tidak berlaku untuk program yang akan memiliki Perilaku Tidak Terdefinisi di masa depan.
sumber