2009-04-19 37 views
6

Có một bài đăng của Raymond Chen, nơi he tells how bad IsBadXxxPtr function is by eating guard page exception.Ngoại lệ trang bảo vệ trong Delphi?

Tôi không hoàn toàn hiểu cách áp dụng cho Delphi. Ai và như thế nào nên bình thường (tức là không có cuộc gọi đến IsBadXxxPtr) xử lý ngoại lệ này? Tôi biết rằng Delphi chèn mã, mà (ví dụ) truy cập bộ nhớ cho các mảng tĩnh lớn - chính xác vì lý do này: để mở rộng ngăn xếp.

Nhưng nếu ngoại lệ trang bảo vệ được nâng lên: ai sẽ xử lý nó trong ứng dụng Delphi? Tôi không thể vô tình gây rối với nó bằng cách sử dụng try/except theo cách không thích hợp? Trình gỡ rối của Delphi có thông báo cho tôi về những ngoại lệ này không?

+1

Sao lưu một khoảnh khắc. Bạn cần gọi một trong những hàm IsBadXXXPtr để làm gì? – jmucchiello

+0

Tôi không cần bất kỳ IsBadXXXPtr (Tôi đồng ý với Raymond - nó là tốt hơn để sụp đổ trong những trường hợp này). Tôi chỉ phát hiện ra rằng tôi không biết, tình hình này được xử lý như thế nào trong Delphi. Đó là lý do tại sao tôi hỏi - chỉ vì tò mò. – Alex

+0

Mã nào bạn "biết" Delphi chèn để mở rộng ngăn xếp khi truy cập các mảng tĩnh lớn? Tôi chưa bao giờ thấy bất cứ thứ gì thuộc loại này. –

Trả lời

13

Xử lý ngoại lệ có cấu trúc Windows (SEH) có cấu trúc hai pha. Khi ngoại lệ xảy ra, trước tiên Windows sẽ tìm một trình xử lý ngoại lệ bằng cách theo chuỗi xử lý ngoại lệ đã đăng ký (phần đầu được lưu trữ trong fs: [0] trên x86, tức là từ đầu tiên trong phân đoạn được chỉ ra bởi phân đoạn FS đăng ký - tất cả các logic phân đoạn bù đắp 16 bit xấu xí đó không biến mất trong 32 bit, nó chỉ trở nên ít liên quan hơn).

Tìm kiếm được thực hiện bằng cách gọi hàm có cờ cụ thể, con trỏ được lưu trữ trong mỗi khung ngoại lệ trên ngăn xếp. fs: [0] trỏ tới khung trên cùng. Mỗi khung trỏ đến khung trước đó. Cuối cùng, khung cuối cùng trong danh sách là một khung đã được cung cấp bởi hệ điều hành (trình xử lý này sẽ bật lên một hộp thoại ứng dụng sụp đổ nếu một ngoại lệ chưa được giải quyết đạt tới nó).

Các chức năng này thường kiểm tra loại ngoại lệ và trả lại mã để cho biết phải làm gì. Một trong những mã có thể được trả về về cơ bản là "bỏ qua ngoại lệ này và tiếp tục". Nếu Windows thấy điều này, nó sẽ thiết lập lại con trỏ lệnh đến điểm ngoại lệ và tiếp tục thực hiện. Một mã khác cho biết rằng khung ngoại lệ này sẽ xử lý ngoại lệ đã cho. Mã thứ ba là "Tôi sẽ không bắt ngoại lệ này, hãy tiếp tục tìm kiếm". Windows tiếp tục gọi các hàm bộ lọc ngoại lệ này cho đến khi nó tìm thấy một hàm xử lý ngoại lệ theo cách này hay cách khác.

Nếu Windows tìm thấy một xử lý ngoại lệ bằng cách bắt nó, nó sẽ tiến hành giải phóng ngăn xếp trở lại trình xử lý đó, bao gồm gọi lại tất cả các chức năng, chỉ chuyển sang một cờ khác. Vào thời điểm này, các hàm thực thi logic finally, cho đến khi trình xử lý thực hiện logic except.

Tuy nhiên, với ngoại lệ bảo vệ trang ngăn xếp, quá trình này khác. Không có trình xử lý ngoại lệ của ngôn ngữ nào sẽ chọn xử lý ngoại lệ này, bởi vì nếu không thì cơ chế tăng trưởng ngăn xếp sẽ bị phá vỡ.Thay vào đó, bộ lọc tìm kiếm lọc toàn bộ bộ xử lý ngoại lệ được cung cấp bởi hệ điều hành, tăng phân bổ stack bằng cách cam kết bộ nhớ thích hợp, và sau đó trả về mã trả về thích hợp để chỉ ra rằng hệ điều hành sẽ tiếp tục ở nơi nó bị tắt, thay vì thư giãn ngăn xếp.

Công cụ và cơ sở hạ tầng gỡ lỗi được thiết kế để cho các ngoại lệ cụ thể này phát ra chính xác, vì vậy bạn không cần phải lo lắng về việc xử lý chúng.

Bạn có thể đọc thêm về SEH theo số Matt Pietrek's excellent article in MSJ from over a decade ago.

+0

Trong Delphi, không thể chỉ định kết quả "bỏ qua điều này và tiếp tục", phải không? Vì vậy, bạn không thể thiết lập một trang bảo vệ trong Delphi ngay cả khi bạn muốn, tách biệt với bất kỳ hạt nhân nào cung cấp. Ngôn ngữ không thực sự phơi bày mọi thứ mà SEH cung cấp, và nếu nó đã làm, Linux và .Net có lẽ sẽ khó khăn hơn nhiều để chuyển đến, phải không? –

+1

Rob - bạn có thể chỉ định bất cứ điều gì bạn thích nếu bạn thiết lập khung ngoại lệ cho mình, đòi hỏi một bộ lắp ráp nhỏ. Các ngoại lệ .NET hỗ trợ một cái gì đó được gọi là các bộ lọc ngoại lệ, ánh xạ tới giai đoạn tìm kiếm của SEH, nhưng chúng chỉ được hiển thị trong cú pháp ILASM và Visual Basic cho .NET, theo hiểu biết của tôi. WRT Linux, tôi đã không nhìn sâu vào cơ chế được sử dụng bởi dcc, nhưng nó là một cơ chế PC-ánh xạ, và cho đơn giản, tôi nghi ngờ nó không phải là hai pha. –

+0

(Cơ chế ngoại lệ PC-ánh xạ trong Kylix hoàn toàn được thực hiện bởi trình biên dịch và RTL, vì Linux không có một cơ chế ngoại lệ bên ngoài cơ chế tín hiệu lại thấp hơn rất giống nhau.) –

2

Từ việc xem xét nhận xét, có vẻ như tôi giống như "sự cố ngoại lệ trang bảo vệ" diễn ra hoàn toàn bên trong hạt nhân và không phải là điều bạn cần lo lắng từ không gian người dùng.

Bạn phải nhớ rằng bài viết này được viết cho C++, không ở đâu gần như cao cấp như Delphi ở mặt trước quản lý bộ nhớ. Các vấn đề con trỏ uninitialized là ít hơn rất nhiều của một mess trong Delphi hơn trong C/C++ vì hai lý do:

  1. Delphi kiểm tra các biến uninitialized tại thời gian biên dịch, mà (vì lý do gì) rất nhiều C trình biên dịch có xu hướng gặp rắc rối với.
  2. Delphi khởi tạo tất cả bộ nhớ động của nó thành 0, vì vậy bạn không có rác heap ngẫu nhiên để xử lý mà có thể trông giống như một con trỏ tốt khi nó thực sự không. Điều này có nghĩa là hầu hết các con trỏ xấu đều cung cấp cho bạn các vi phạm truy cập, dễ dàng để gỡ lỗi, thay vì âm thầm thất bại và làm hỏng bộ nhớ.
Các vấn đề liên quan