2010-03-23 18 views
8

Chúng ta có một phần lớn mã C++ gốc, được biên dịch thành các tệp DLL.Các cấu trúc không được gọi khi ngoại lệ gốc (C++) lan truyền đến thành phần CLR

Sau đó, chúng tôi có một vài dll chứa mã proxy C++/CLI để bọc giao diện C++.

Trên hết, chúng tôi có mã C# gọi vào trình bao bọc C++/CLI.

Công cụ chuẩn, cho đến nay.

Nhưng chúng tôi có rất nhiều trường hợp ngoại lệ gốc C++ được phép truyền tới thế giới .Net và chúng tôi dựa vào khả năng của .Net để bọc chúng dưới dạng đối tượng System.Exception và phần lớn hoạt động tốt.

Tuy nhiên, chúng tôi đã nhận thấy rằng các trình phá hủy của các đối tượng trong phạm vi tại điểm ném không được gọi khi ngoại lệ lan truyền!

Sau một số nghiên cứu, chúng tôi thấy rằng đây là vấn đề khá nổi tiếng. Tuy nhiên các giải pháp/cách giải quyết dường như ít nhất quán. Chúng tôi đã thấy rằng nếu mã gốc được biên dịch bằng/EHa thay vì/EHsc thì vấn đề sẽ biến mất (ít nhất là trong trường hợp thử nghiệm của chúng tôi). Tuy nhiên, chúng tôi rất thích sử dụng/EHsc vì chúng tôi dịch ngoại lệ SEH sang ngoại lệ C++ và chúng tôi muốn cho phép trình biên dịch có phạm vi tối ưu hóa hơn.

Có cách giải quyết nào khác cho vấn đề này - ngoài việc gói mọi cuộc gọi qua ranh giới được quản lý tự nhiên trong một thử (bắt nguồn) (ngoài lớp C++/CLI)?

+0

bạn có tìm thấy câu trả lời đúng cho số này –

+0

Tôi không nhớ bây giờ, thật không may. – philsquared

Trả lời

2

Thật không may là tôi không tin rằng có bất kỳ cách giải quyết tốt nào. Việc thực thi ngoại lệ C++ trên các nền tảng MS được thực hiện bằng cách sử dụng các ngoại lệ SEH (IIRC). CLR móc vào xử lý SEH để bắt các ngoại lệ gốc và xử lý chúng thành các ngoại lệ CLR. Vì nó bắt chúng ở mức SEH ngoại lệ trông giống như một ngoại lệ SEH cho C++ và các destructors được chạy hoặc không chạy tương ứng.

Vì vậy, khi bạn đã ghi nhận hai lựa chọn tốt nhất là

  • Compile với/EHA
  • Thêm một try/catch tại điểm xuất nhập cảnh của các chức năng của bạn

Lý tưởng nhất là bạn nên làm cái thứ hai. Theo kinh nghiệm của tôi nó được coi là thực hành xấu để cho phép ngoại lệ C++ để vượt qua ranh giới thành phần.

Cũng có khả năng một giải pháp hacky bạn có thể đạt được bằng cách sử dụng _set_seh_translator (Documentation). Tuy nhiên tôi khuyên bạn nên tránh chức năng đó vì nó có thể vô tình phá hủy xử lý ngoại lệ CLR và gây ra rất nhiều vấn đề không mong muốn.

+0

Chúng tôi đang thực sự sử dụng SetUnhandledExceptionFilter() (xem phản hồi của tôi với @nobugz) và chúng tôi đang tính đến các ngoại lệ CLR trong việc xử lý đó. Đối với ngoại lệ C++ vượt qua ranh giới thành phần: (1) Lời hứa là điều này sẽ tự động được xử lý cho chúng tôi theo thời gian chạy - và, ngoài vấn đề này, nó là. (2) Nếu chúng ta làm điều đó, nơi logic sẽ nằm trong mã proxy C++/CLI của chúng ta. Nhưng bởi vì đó là mã CLI đã quá muộn để bắt gặp vấn đề này. Vì vậy, để đi xuống con đường đó chúng tôi có hiệu quả phải có hai lớp gói (một bản địa, một quản lý)! – philsquared

2

Bạn không làm điều này đúng. Sử dụng _set_se_translator() đã yêu cầu bạn biên dịch với/EHa. Từ MSDN Library page:

You must use /EHa when using _set_se_translator. 

Nghiêm trọng hơn, bạn sẽ phá vỡ mã số quản lý khi bạn sử dụng nó. CLR dựa vào ngoại lệ SEH để phát hiện các rủi ro khác nhau. Nó sử dụng SetUnhandledExceptionFilter để bẫy chúng. Đặc biệt NullReferenceException và OverflowException (x86) được nâng lên theo cách này. Khi bạn tiêm khối __try của riêng mình, bạn sẽ ngăn chặn ngoại lệ này chảy vào CLR.Mặc dù bạn sẽ "xử lý" nó, bạn sẽ không có bất kỳ dấu vết của lý do chính xác cho ngoại lệ. Và các khối try/catch được quản lý không thể phát hiện ra nó.

Hiệu quả chữa bệnh/EHa (nếu thực sự là vấn đề) là mã 64 bit. Chức năng của nó dựa trên stack thư giãn là rất hiệu quả với số không trên không cho một khối thử.

+0

Chúng tôi thực sự sử dụng SetUnhandledExceptionFilter(). Chúng tôi thực hiện chuỗi các bộ lọc được đăng ký đầy đủ, vì vậy nếu có trình xử lý ở phía bên .Net của hàng rào vẫn đang xem xét (đó là những gì đang xảy ra trong trường hợp câu hỏi được nhắc). Sử dụng mã 64 bit không phải là một tùy chọn cho chúng tôi vì đây là một khung công tác phải có khả năng chạy trên máy tính để bàn (nơi tiêu chuẩn hiện tại của chúng tôi là XP). – philsquared

3

Trang MSDN cho switch/E trình biên dịch hiện trạng thái hành vi này: -

http://msdn.microsoft.com/en-us/library/1deeycx5(VS.80).aspx

Dưới đây là trích dẫn có liên quan: -

Nếu bạn sử dụng/EHS, sau đó bắt bạn Điều khoản sẽ không bắt được ngoại lệ không đồng bộ. Ngoài ra, trong Visual C++ 2005, tất cả các đối tượng trong phạm vi khi ngoại lệ không đồng bộ được tạo sẽ không bị hủy ngay cả khi ngoại lệ không đồng bộ được xử lý.

Về cơ bản/EHsc là chế độ xem lạc quan - giả định rằng ngoại lệ duy nhất là kiểu dáng C++ chính xác và sẽ tối ưu hóa cho phù hợp./Mặt khác, EHa có quan điểm bi quan và giả định rằng bất kỳ dòng mã nào cũng có thể gây ra ngoại lệ.

Nếu bạn có thể đảm bảo rằng bạn sẽ không bao giờ gây ra vi phạm quyền truy cập hoặc lỗi trong trang hoặc SEH khác thì hãy sử dụng/EHsc. Nhưng nếu bạn đang viết một dịch vụ và/hoặc muốn cung cấp một "nỗ lực tốt nhất" thì/EHa là cần thiết.

Tôi cũng đồng ý với ý kiến ​​của @ JaredPar về việc không cho phép ngoại lệ vượt qua ranh giới mô-đun. Điều gì @nobugz nói về cách CLR xử lý các ngoại lệ có thể đúng, nhưng tôi nghĩ có sự khác biệt giữa mã .Net gọi trực tiếp tới mã nguồn gốc bằng cách sử dụng P/Invoke và gọi vào một DLL tương tác C++/CLI. Trong trường hợp trước, CLR phải xử lý tình huống thay cho bạn, trong khi đó, bạn phải kiểm soát và có thể dịch cho phù hợp.

+0

Cảm ơn Chris. Tuy nhiên, trường hợp trong câu hỏi của tôi là với ngoại lệ C++. Đối với việc vượt qua ranh giới mô-đun, tôi sẽ bình luận về phản ứng của @ JaredPar. – philsquared

+0

Xin lỗi tôi đã tập trung vào bit/EHa. Bạn đang nói rằng bạn nhìn thấy nó ngay cả với một ném bình thường? ví dụ.ném std :: runtime_error(); –

+0

có. Ngay cả với 'ném 42;' – philsquared

1

Có lỗi trong phiên bản 2.0 của CLR gây ra sự cố này. Chạy tệp thực thi được quản lý của bạn trên 4.0 CLR sẽ cho phép trình phá hủy được gọi như mong đợi.

Xem Boost shared mutex not released after exception thrown để biết chi tiết.

+0

Xem thêm http://connect.microsoft.com/VisualStudio/feedback/details/382860/ehsc-eha-stack-unwinding –

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