2009-08-26 56 views
48

Tôi tò mò muốn biết điều gì sẽ xảy ra khi ngăn xếp và vùng heap va chạm. Nếu bất cứ ai đã gặp phải điều này, xin vui lòng họ có thể giải thích kịch bản.Điều gì sẽ xảy ra khi Stack và Heap Collide

Xin cảm ơn trước.

+7

Tôi chắc chắn điều đó xảy ra khi bạn không thể ngăn chặn tổn thương bên trong –

+1

Vâng của bạn ra khỏi bộ nhớ ngăn xếp và ra khỏi bộ nhớ Heap một OutOfMemoryException có thể được ném? – CodingBarfield

+18

Tôi không đồng ý với các phiếu bầu (NaRQ). Tình huống được mô tả * là * thực, * là * quan trọng trong các hệ thống nhỏ ngay cả ngày hôm nay, * là * xấu, và * là * đáng hiểu. – dmckee

Trả lời

56

Trong ngôn ngữ hiện đại chạy trên hệ điều hành hiện đại, bạn sẽ bị tràn ngăn xếp (hurray!) Hoặc malloc() hoặc sbrk() hoặc mmap() sẽ không thành công khi bạn cố gắng phát triển vùng heap. Nhưng không phải tất cả các phần mềm hiện đại, vì vậy chúng ta hãy nhìn vào chế độ thất bại:

  • Nếu stack phát triển thành đống, C biên dịch thường sẽ âm thầm bắt đầu ghi đè lên cấu trúc dữ liệu của heap. Trên một hệ điều hành hiện đại, sẽ có một hoặc nhiều bộ nhớ ảo các trang bảo vệ ngăn không cho ngăn xếp phát triển vô thời hạn. Miễn là số lượng bộ nhớ trong các trang bảo vệ ít nhất là lớn như kích thước của hồ sơ kích hoạt của quy trình phát triển, hệ điều hành sẽ đảm bảo cho bạn một segfault. Nếu bạn đang chạy DOS trên một máy không có MMU, có lẽ bạn đang bị hosed.

  • Nếu heap phát triển trong ngăn xếp, hệ điều hành phải luôn nhận thức được tình huống và một số loại cuộc gọi hệ thống sẽ không thành công. Việc thực hiện malloc() gần như chắc chắn nhận thấy sự thất bại và trả về NULL. Điều gì xảy ra sau đó là tùy thuộc vào bạn.

Tôi luôn ngạc nhiên trước sự sẵn sàng của các nhà biên dịch để hy vọng rằng hệ điều hành đặt các trang bảo vệ tại chỗ để ngăn chặn tràn ngăn xếp. Tất nhiên, thủ thuật này hoạt động tốt cho đến khi bạn bắt đầu có hàng ngàn chủ đề, mỗi stack riêng của mình ...

+1

Ngay cả với một chủ đề duy nhất, nó có thể nhận được va chạm đống rác không bị phát hiện: https://gcc.gnu.org/ml/gcc-help/2014-07/msg00076.html (mặc dù điều này là khá khó xảy ra trong thực hành, có lẽ ngoại trừ trong trường hợp tấn công cụ thể). Trang GCC man khuyên sử dụng cờ '-fstack-check' với các chương trình đa luồng (và cờ này cũng cho phép va chạm được phát hiện trong ví dụ của tôi). – vinc17

4

Bạn nhận được ngoại lệ bộ nhớ hoặc ngoại lệ ngăn xếp nếu bạn may mắn. Nếu bạn không may mắn, chương trình sẽ chuyển sang bộ nhớ không hợp lệ và ném một ngoại lệ bộ nhớ xấu. Nếu bạn vô cùng không may mắn, chương trình sẽ tiếp tục và phát hiện một thứ gì đó không nên và bạn không bao giờ biết tại sao chương trình của bạn lại thất bại.

Cuối cùng, vũ trụ có thể bị nứt.

+1

+1 Vũ trụ MS-DOS đã bị bẻ khóa nhưng chúng tôi chưa thấy sự bùng nổ – ATorras

+1

Lưu ý rằng tràn ngăn xếp không thể là ngoại lệ C++. – AProgrammer

+0

@atorras - MSDOS vũ trụ sẽ không bị nứt cho đến khi họ giải thưởng cho lệnh ra khỏi tay chết lạnh của tôi :-) –

42

Điều này phụ thuộc vào nền tảng. Trên nhiều nền tảng nó thực sự không thể xảy ra ở tất cả (đống và ngăn xếp được phân bổ trong các trang khác nhau và ne'r twain sẽ đáp ứng.

Hãy nhớ rằng ý tưởng của đống ngày càng tăng lên và ngăn xếp phát triển xuống Trên các hệ thống rất nhỏ (giống như vi 8-bit cũ chạy CP/M) và trên một số PIC và các hệ thống mô hình bộ nhớ phẳng khác (những người không có MMU hoặc bất kỳ bộ nhớ ảo hoặc bảo vệ nào khác) thì Trong trường hợp đó, hành vi sẽ không được xác định ... nhưng nó gần như chắc chắn sẽ sụp đổ ngay sau khi mã cố gắng quay trở lại một số địa chỉ trên đỉnh của ngăn xếp bị hỏng hoặc theo một con trỏ gián tiếp từ một một phần của heap khác hoặc ...

Trong mọi trường hợp bạn w không nhìn thấy nó trên bất kỳ máy trạm hoặc máy chủ mục đích chung hiện đại nào. Bạn sẽ đạt đến giới hạn tài nguyên và gặp phải lỗi malloc, hoặc bạn sẽ chạy vào bộ nhớ ảo và cuối cùng hệ thống sẽ tự đẩy nó vào đống run rẩy "nhấn nút chuyển màu đỏ."

+8

+1 Đối với vui nhộn và sử dụng, "ne'er twain." –

11

Trong những thời điểm như những đó là thời gian để biến những lời nhà hiền triết của Tiến sĩ Egon Spengler ....

  • Tiến sĩ Egon Spengler: Có điều gì đó rất quan trọng tôi quên nói với bạn.
  • Dr.Peter Venkman: Cái gì?
  • Tiến sĩ Egon Spengler: Đừng để đống rác va chạm với chồng.
  • Tiến sĩ Peter Venkman: Tại sao?
  • Tiến sĩ Egon Spengler: Sẽ rất tệ.
  • Tiến sĩ Peter Venkman: Tôi hơi mờ về toàn bộ điều "tốt/xấu" ở đây. Ý bạn là "xấu"?
  • Tiến sĩ Egon Spengler: Cố gắng tưởng tượng mọi sự sống khi bạn biết nó ngừng ngay lập tức và mọi phân tử trong cơ thể bạn phát nổ với tốc độ ánh sáng.
  • Tiến sĩ Ray Stantz: Tổng số đảo ngược protonic!
  • Tiến sĩ Peter Venkman: Thật tệ. Đuợc. Tất cả, mẹo an toàn quan trọng. Cảm ơn, Egon.
+1

Thật kỳ lạ, cụm từ mà tôi nghĩ đến là "chó và mèo sống với nhau" – plinth

+0

Minh họa tuyệt vời. Hy vọng rằng 'universed -debug' giải phóng tất cả bộ nhớ của nó! – new123456

1

Bạn sẽ nhận được lỗi phân đoạn hoặc lỗi phân bổ bộ nhớ nếu xảy ra tràn ngăn xếp/đống. Dưới đây là ví dụ:

void recursiveFun() 
{ 
    static int i; 
// char *str= (char *)malloc (100); 
    printf ("%d\t", i++); 
    recursiveFun(); 
// free (str); 
} 

Giả sử, bạn gọi hàm ở trên, nó sẽ hết chồng và chương trình sẽ bị lỗi. Bây giờ, loại bỏ các dòng nhận xét và gọi lại chức năng, bạn sẽ tìm thấy lỗi phân đoạn xảy ra trong thời gian ít hơn và ít đệ quy hơn phiên bản trước đó. [Trong môi trường thử nghiệm của tôi, Stack Overflow xảy ra sau khi 5237765 đệ quy trong trường hợp đầu tiên, trong khi trong kịch bản thứ hai nó xảy ra sau khi 2616325 đệ quy.]

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