Có tràn bộ đệm thay đổi loại dữ liệu của biến nó là ghi đè? [đóng cửa]


8

Nói rằng tôi có một mảng ký tự C char buf[15]. Nói biến int set_me = 0có dữ liệu của nó được lưu trữ trong một vị trí bộ nhớ trực tiếp sau char buf[15]. Nếu tôi tràn bufchuỗi "aaabbbcccdddeee\xef\xbe\xad\xde", set_mekiểu dữ liệu sẽ thay đổi từ số nguyên sang mảng ký tự?


3
Phụ thuộc vào người đang diễn giải dữ liệu. cuối cùng mọi thứ là nhị phân. Vì vậy, theo cách bạn diễn giải nó, nó có thể là một giá trị nguyên hợp lệ hoặc gây ra lỗi cast
Ganesh R.

Câu trả lời:


33

Không.

"Kiểu dữ liệu" của một biến chỉ có liên quan trong mã nguồn (và thậm chí sau đó chỉ trong một số ngôn ngữ). Nó cho trình biên dịch biết cách xử lý biến.

Các kiểu dữ liệu mức cao này không tồn tại như vậy trong mã được biên dịch (nguyên gốc). Chúng có thể ảnh hưởng đến những gì trình biên dịch tạo ra, nhưng bản thân các hướng dẫn không quan tâm nếu dữ liệu đại diện cho một ký tự hoặc một số.


Các biến không tồn tại trong phần cứng. Trong phần cứng, bạn có các vị trí bộ nhớ và các hướng dẫn hoạt động trên chúng.

Một biến có thể được xem là chế độ xem dữ liệu tại một vị trí bộ nhớ - nếu bạn nheo mắt và nhìn vào cùng một bộ nhớ khác nhau (một biến khác nhau với loại khác nhau tham chiếu đến cùng một vị trí), cùng một giá trị nhị phân có thể có ý nghĩa khác .

Ví dụ, byte 0x41 có thể được hiểu là ký tự được mã hóa UTF-8 A. Nó cũng có thể được hiểu là số nguyên byte đơn 65. Nó cũng có thể được hiểu là một byte trong một số nguyên hoặc số dấu phẩy động nhiều byte hoặc một byte trong mã hóa ký tự nhiều byte. Nó có thể là bitet 0b1000001. Tất cả từ cùng một byte trong cùng một vị trí bộ nhớ. Trong ngôn ngữ C, bạn có thể thấy hiệu ứng này bằng cách đúc cho các loại khác nhau.

Khi bạn có "lỗi tràn bộ đệm", bạn đang làm gì đó ngoài giới hạn của trình biên dịch hoặc ngôn ngữ của bạn. Nhưng, theo như phần cứng liên quan đến 1 , bạn đang ghi byte (dù là đơn hay nhiều) vào một vị trí bộ nhớ. Một vị trí bộ nhớ không có "loại". Trong thực tế, phần cứng thậm chí không biết rằng bất kỳ tập hợp byte cụ thể nào tạo ra một mảng hoặc bộ đệm trong mã của bạn.

Bất cứ nơi nào bạn truy cập tiếp theo vị trí bộ nhớ trong mã của bạn, các hướng dẫn sẽ chạy như được xác định ban đầu. ví dụ: nếu họ đang mong đợi một số ở đó, họ sẽ hành động trên bất kỳ byte dữ liệu nào như thể chúng là một số.


Để sử dụng ví dụ của bạn, giả sử bạn intlà số nguyên 4 byte (32 bit) đã ký:

+-------------+--------------------------------------------+-----------+
| Source code |                  char[15]                  |    int    |
+-------------+--------------------------------------------------------+
| Memory      |61|61|61|62|62|62|63|63|63|64|64|64|65|65|65|EF|BE|AD|DE|
+-------------+--------------------------------------------------------+

Bạn có thể thấy rằng intvị trí bộ nhớ của bây giờ chứa 0xEFBEADDE, giả sử một hệ thống cuối lớn 2 . Đây là int 32-bit đã ký -272716322. Bây giờ, nếu bạn diễn giải cùng một bộ nhớ như một int ( uint) không dấu , thì nó sẽ 4022250974thay thế. Đối với chính xác cùng một dữ liệu trong bộ nhớ, ý nghĩa hoàn toàn phụ thuộc vào cách bạn xem nó.


1 Có một số cơ chế ngăn bạn ghi vào các vùng bộ nhớ được bảo vệ và sẽ làm hỏng chương trình của bạn nếu bạn cố làm như vậy.

2 x86 thực sự là endian nhỏ, có nghĩa là bạn diễn giải các byte tạo thành một giá trị lớn hơn về phía sau. Vì vậy, trên x86, thay vào đó bạn sẽ có 0xDEADBEEF, ký tên -559038737hoặc không dấu 3735928559.


Vì vậy 0xdeadbeef, trên kiến ​​trúc x86, sẽ chiếm ít không gian trong bộ nhớ hơn so với đối tác thập phân của nó , 3735928559?
Darien Springer

2
@DarienSpringer Cả hai chiếm 4 byte bộ nhớ - chúng là cùng một chuỗi 4 byte. Chúng giống hệt nhau trong bộ nhớ. Bạn có thể coi tất cả là cơ sở 2 (nhị phân) trong bộ nhớ, nếu bạn muốn. Sau đó, khi bạn hiển thị chúng (chuyển đổi thành chuỗi cho đầu ra), bạn có thể chọn cơ sở để hiển thị - hex là cơ sở 16 và thập phân là cơ sở 10. Các biểu diễn chuỗi được lưu trữ ở một vị trí bộ nhớ khác và có thể sử dụng các lượng khác nhau của bộ nhớ (vì mỗi ký tự là một byte riêng biệt). Các chuỗi 0xDEADBEEF được lưu trữ trong bộ nhớ như 0x30 0x78 0x44 0x45 0x41 0x44 0x42 0x45 0x45 0x46.
Bob

5
@DarienSpringer Đặt một cách khác, một số là cùng một số cho dù đó là cơ sở nào. Hex là một cách thuận tiện (nhỏ gọn) để xem nhị phân. Về mặt vật lý, đó là nhị phân. Con người thích số thập phân, vì vậy chúng ta thường hiển thị số dưới dạng số thập phân. Nhưng cho đến khi chúng ta đến bước hiển thị, tất cả các phép toán số (cộng, trừ, nhân, v.v.) đều hoạt động trên cùng một dữ liệu nhị phân trong bộ nhớ.
Bob

1
"Bạn có thể thấy rằng vị trí bộ nhớ của int bây giờ là 0xEFBEADDE" Nitpick: Tôi biết bạn không có ý định này, nhưng có vẻ như bạn đang nói int nằm vị trí bộ nhớ 0xEFBEADDE. Có lẽ tua lại một chút. Mặt khác, đây là một câu trả lời tuyệt vời - Tôi đặc biệt thích sự tương tự "xem" và ý tưởng "nheo mắt" :)
Các cuộc đua Lightness trong quỹ đạo

@LightnessRacesinOrbit Điểm tốt. Đã chỉnh sửa.
Bob

2

Từ góc độ C, câu trả lời sẽ là "Ai biết được? Đó là hành vi không xác định".

Các loại là một khái niệm C, không phải phần cứng. Nhưng các quy tắc C không áp dụng nếu chương trình của bạn có Hành vi không xác định, đó là nghĩa đen của Hành vi không xác định trong tiêu chuẩn C. Và tràn bộ đệm là một dạng của điều đó.

Ban đầu tôi đã viết "các quy tắc C không còn áp dụng", nhưng trên thực tế, Hành vi không xác định là hồi tố. Các quy tắc C không áp dụng cho một chương trình sẽ có Hành vi không xác định trong tương lai.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.