2009-11-17 36 views
5

Tôi nhận được kết quả lạ trong mã C sau.malloc() và bộ nhớ heap

int main() 
{ 
    int *p = (int *) malloc(100); 
    p[120] = 5; 
    printf("\n %d", p[120]); 
} 

Vì tôi chỉ phân bổ 100 byte nên mã này sẽ gây ra lỗi phân đoạn. Tuy nhiên, nó in '5' và không đưa ra bất kỳ lỗi thời gian chạy nào. Bất cứ ai có thể vui lòng giải thích lý do?

+4

Có lẽ chỉ có may mắn. –

+5

Bạn đã viết 5 đến một địa điểm không thuộc về bạn. Nếu chủ nhân của nơi đó không thích những gì bạn đã làm cho nhà của mình, nó sẽ được trả thù. ** Cẩn thận **, nó có thể thuộc về trình điều khiển đĩa USB của bạn và nó sẽ định dạng ổ đĩa tiếp theo bạn đặt vào. – pmg

+4

@pmg: Thực tế, điều đó không có khả năng trên hệ điều hành chế độ bảo vệ hiện đại. – bcat

Trả lời

20

Không, mã không nên (nhất thiết) đưa ra sự phân đoạn. Một segfault xảy ra khi bạn cố gắng truy cập vào một trang bộ nhớ ảo không được cấp phát cho quá trình của bạn.

"Heap" hoặc "cửa hàng miễn phí" là vùng của các trang bộ nhớ ảo thuộc sở hữu của quy trình của bạn. API malloc() chia phân vùng này thành các khối và trả về một con trỏ tới khối.

Nếu bạn địa chỉ ngoài phần cuối của khối mà bạn có một con trỏ, bạn thường sẽ truy cập vào bộ nhớ là một phần của đống, nhưng không phải là một phần của khối được phân bổ của bạn. Bằng cách này, bạn có thể làm hỏng các khối heap khác hoặc thậm chí là các cấu trúc dữ liệu mà malloc() sử dụng để xác định vùng heap.

Để biết thêm thông tin về tham nhũng heap, và phương pháp để phát hiện nó trong phiên bản debug mã của bạn, đây là một cuốn sách tuyệt vời:

Writing Solid Code: Microsoft's Techniques for Developing Bug-Free C Programs by Steve Maguire alt text http://ecx.images-amazon.com/images/I/5148TK6JCVL._BO2,204,203,200_PIsitb-sticker-arrow-click,TopRight,35,-76_AA240_SH20_OU01_.jpg

Một phụ lục cho pedantic: Trong những trường hợp hiếm , bằng cách truy cập bộ nhớ ngoài phần cuối của khối heap, bạn có thể truy cập bộ nhớ không phải là một phần của heap. Trong những trường hợp này, bạn có thể gặp lỗi phân đoạn mà bạn mong đợi. Bạn cũng có thể làm hỏng một số cấu trúc dữ liệu khác so với heap. Nó thực sự là một vấn đề của cơ hội. Tuy nhiên, heap chính nó là rất lớn so với khối heap điển hình, do đó, 99% của mã thời gian như ví dụ của bạn sẽ bị hỏng heap. Ví dụ bạn cung cấp rơi vào trường hợp 99% đó.

+0

Thực ra, kể từ khi anh ấy yêu cầu thay đổi 20 byte qua cuối ngăn xếp, tùy thuộc vào kiến ​​trúc và mã xung quanh, anh ta có thể thay thế ngăn xếp hoặc thậm chí thay đổi chương trình. Hành vi này thực sự không xác định. –

+2

T.E.D. Đó chỉ là "loại" đúng. Anh ta không nghi ngờ gì khi sử dụng một máy có kích thước trang bộ nhớ ảo. Có lẽ mã thực thi có bảo vệ VM khác với heap. Tôi sẽ đặt cược anh ta trên một hệ thống như vậy bởi vì hàm chuẩn malloc() của thư viện C tồn tại. Những gì bạn viết là đúng, tuy nhiên, đặc biệt là trên Radio Shack Model III chạy TRS-DOS trên một Z-80. ;) –

+0

Và có, ngay cả trên một hệ thống trang VM, những gì bạn viết có thể xảy ra. Nó không phải là có khả năng và nó không phải là rất sư phạm để đi vào chi tiết đó hiếm khi có vấn đề. Giải quyết vấn đề ở cấp độ mà nó được tuyên bố. Tránh việc đi bộ. –

0

Bạn đang viết vào bộ nhớ mà bạn chưa phân bổ. Chương trình cuối cùng có thể chấm dứt do tác động của tham nhũng đống nếu thời gian chạy của nó đủ dài.

6

Truy cập bộ nhớ không hợp lệ sẽ không phải lúc nào cũng gây ra lỗi phân đoạn, lỗi bus hoặc sự cố khác. Ví dụ: nếu có một khối khác được phân bổ ngay sau mảng của bạn, bạn sẽ thay đổi các giá trị trong khối - đó có thể là bất kỳ thứ gì.

0

Bạn đang ghi vào bộ nhớ chưa được khởi tạo; điều này được cho phép trong C, nó không phải là một ý tưởng hay. Loại điều này không nhất thiết phải gây ra lỗi phân đoạn.

+2

Việc bạn sử dụng từ "được phép" là gây hiểu lầm. Đó là cú pháp hợp lệ, nhưng gọi hành vi không xác định. –

3

Không, nó có thể cho segfault, nhưng chỉ khi bộ nhớ nằm ngoài quá trình của bạn. Nếu không nó sẽ chỉ sửa đổi một số khu vực khác của bộ nhớ chương trình của bạn. C không kiểm tra điều này, hoặc bảo vệ bạn bằng bất kỳ cách nào, ngay cả trong những trường hợp hiển nhiên như trên. Nhiều phần mềm crackers sử dụng "tính năng" của C về cơ bản viết lại một chương trình có nâng cao privs, và cung cấp cho mình kiểm soát máy tính của bạn. Nó được gọi là buffer overflow exploit.

Đây là lý do tại sao C (và C++) thực sự nên tránh cho phần mềm mới được ưu tiên cho các ngôn ngữ an toàn hơn như Ada.

+1

Tôi biết câu cuối cùng sẽ khiến tôi bình chọn tiêu cực. Tôi không quan tâm. Đúng rồi. –

+0

+1 từ tôi. Tôi hoàn toàn đồng ý. – lesscode

0

nguyên nhân thường gặp của lỗi segmentation:

  • dereferencing con trỏ có giá trị không hợp lệ
  • dereferencing con trỏ null
  • cố gắng để viết thành một chỉ đọc phân khúc
  • miễn phí-ing con trỏ không đúng hoặc un khối nổi tiếng.

    int * x = 0;

    x = 200;/ nguyên nhân Segmentation Fault */

Segfaults được tạo ra bởi ngoại lệ MMU dựa trên những gì được xác định là một bộ nhớ truy cập bất hợp pháp. Tùy thuộc vào cách hệ điều hành cấu trúc bộ nhớ của nó, một truy cập bộ nhớ trên một hệ điều hành có thể là hợp pháp (mặc dù sai) và trên một hệ điều hành khác nó có thể là bất hợp pháp.

+0

Đây là năm muộn, nhưng ... x = 200 là tốt, * x = 200 dẫn đến segfault. –

Các vấn đề liên quan