2012-03-26 28 views
18

Tôi đang gặp phải tình huống trong đó cuộc gọi PInvoke tới CloseHandle đang ném SEHException trong ứng dụng .NET 4 khi chạy trong trình gỡ lỗi. Không giống như others who have encountered similar issues migrating from 3.5 to 4, tôi không đặc biệt bị làm phiền bởi hành vi và đã xác định được sự cố (thư viện của bên thứ ba gọi số CloseHandle hai lần trên cùng một tay cầm). Tuy nhiên, tôi lúng túng là tại sao hành vi này không xảy ra trong một ứng dụng .NET 3.5.Tại sao việc xử lý ngoại lệ từ CloseHandle khác nhau giữa .NET 4 và 3.5?

sau Ví dụ nhỏ nhưng đầy đủ chứng minh hành vi của tôi đang gặp (thử nghiệm trên cả XP SP3 và Win 7 x64, luôn biên soạn như x86):

class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      var hFileMapping = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04 /* read write */, 0, 0x1000, null); 
      CloseHandle(hFileMapping); 
      CloseHandle(hFileMapping); 
      Console.WriteLine("No exception"); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex); 
     } 

     Console.ReadKey(); 
    } 

    [DllImport("kernel32", SetLastError = true)] 
    static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpAttributes, int flProtect, int dwMaximumSizeHigh, int dwMaximumSizeLow, string lpName); 

    [DllImport("kernel32", SetLastError = true)] 
    static extern bool CloseHandle(IntPtr handle); 
} 

Khi chạy như một ứng dụng .NET 4, an SEHException được ném tại số CloseHandle thứ hai. hành vi theo documentation for CloseHandle, điều này được mong đợi:

Nếu ứng dụng đang chạy dưới một trình gỡ lỗi, hàm sẽ ném một ngoại lệ nếu nó nhận được một trong hai giá trị xử lý mà không là hợp lệ hay một giá trị giả xử lý . Điều này có thể xảy ra nếu bạn đóng một handle hai lần, hoặc nếu bạn gọi CloseHandle trên một tay cầm được trả về bởi hàm FindFirstFile thay vì gọi hàm FindClose.

Tuy nhiên, khi biên soạn như một ứng dụng .NET 3.5 (hoặc CLR 2.0), không có ngoại lệ được ném vào thứ hai CloseHandle cuộc gọi, và thông điệp "No exception" được in ra.

Theo this article, CLR được cập nhật phát hành cho .NET 4 có một số hành vi mặc định khác nhau với các ngoại lệ cấp thấp có khả năng làm hỏng trạng thái quy trình. Tuy nhiên, theo như tôi có thể hiểu từ bài viết đó, không có gì được đề cập đến trong hành vi CLR trước đó sẽ khiến cho ngoại lệ bị bỏ qua hoàn toàn.

Tại sao ứng dụng .NET 3.5 (hoặc CLR 2.0) không thể hiện hành vi được ghi lại là CloseHandle có trong .NET 4?

+2

Tôi rất vui vì MS đã thực hiện một số cải tiến trong đấu trường này. Tôi gặp khó khăn với các vấn đề ở đây cho các lứa tuổi: http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/b5b7a179-3737-4380-b6cf-843f3e71b317/ – Brannon

+0

Có lẽ trong pre .NET 4 chúng là chỉ cần im lặng bắt và bỏ qua những ngoại lệ đó –

+0

Đó chính là điều tôi quan tâm để tìm ra - tại sao có thể là như vậy :) – jeffora

Trả lời

9

Windows chỉ tạo ngoại lệ SEH khi thấy trình gỡ lỗi được đính kèm. A native trình gỡ lỗi. Có một sự thay đổi trong trình gỡ lỗi .NET 4 được quản lý mà bây giờ làm cho Windows thấy một trình gỡ lỗi như vậy. Tôi không thể tìm thấy bất kỳ liên kết phong nha mà tài liệu chi tiết chính xác của hành vi mới này, xin lỗi.

Chỉnh sửa: Tôi đã tìm thấy một phong nha. Bullet 8 ở dưới cùng của this blog post:

Dưới mui xe, chúng tôi đang xây dựng trên đường ống dẫn gỡ lỗi mẹ đẻ Trong chế độ v2-compat, ICD tiếp tục sở hữu các đường ống dẫn đến quá trình mục tiêu (vì đó là mô hình V2), nhưng đường ống đó không còn là tập hợp các đối tượng IPC được chia sẻ với quá trình đích, mà thay vào đó là cùng một đường dẫn mà trình gỡ lỗi gốc sử dụng. Cụ thể, chúng ta gắn vào một tiến trình bằng cách gọi kernel32! DebugActiveProcess và nhận các sự kiện được quản lý của chúng ta (những thứ dẫn đến các cuộc gọi đến ICorDebugManagedCallback) bằng cách sử dụng kernel32! WaitForDebugEvent. Điều này cũng có nghĩa là kernel32! IsDebuggerPresent hiện trả về true khi thực hiện gỡ lỗi chỉ được quản lý. Điều này cũng có tác dụng phụ tốt để tránh sự cố khi thực hiện gỡ lỗi chỉ khi được quản lý khi một trình gỡ lỗi hạt nhân được bật (hệ điều hành giả định bất kỳ lệnh breakpoint nào xảy ra khi trình gỡ lỗi không được đính kèm sẽ gây ra sự cố trong trình gỡ lỗi hạt nhân) .

Đây không chỉ là một mỹ phẩm sửa chữa btw, dù rằng các cuộc tấn công xử lý rác là cái gì đó giữ nhân viên của Microsoft tỉnh táo vào ban đêm. Phiên bản .NET 4 của CLR được xây dựng với phiên bản CRT để kiểm tra tràn bộ đệm. Khi một được phát hiện, CRT ngay lập tức chấm dứt chương trình. Không có AppDomain.UnhandledException, nó là một sự cố ngay lập tức đối với màn hình nền. Tuy nhiên, mã này thực hiện cùng một điều mà Windows thực hiện, kiểm tra một trình gỡ lỗi gốc và tạo ra một điểm ngắt khi được gắn vào. Do đó, điều quan trọng là trình gỡ lỗi được quản lý bắt đầu trông giống như trình gỡ lỗi gốc, cách duy nhất để chẩn đoán sự cố.

+0

Điều đó cũng sẽ giải thích lý do tại sao nó đột nhiên bắt đầu vi phạm trong .NET 3.5 khi "Debug Native Code" được chọn trong thuộc tính dự án (mà tôi đã phát hiện ra một đêm khác khi cố gắng xem lại điều này). Cảm ơn! – jeffora

+0

Yup, bật hỗ trợ gỡ lỗi không được quản lý trong các phiên bản trước làm cho trình gỡ lỗi gọi WaitForDebugEvent(). –

1

Không thực sự 'tốt' trả lời cho điều này .. 3,5 đã có một lỗi trong SEH đã được cố định trong 4,0 .. Nó đã được ăn ngoại lệ. Tôi đã có một vấn đề tương tự và chúng tôi đã mở một vé với MSFT trên đó - câu trả lời của họ là 'bugfix'.

+0

Bạn đã mở yêu cầu Kết nối chưa? Nếu có, bạn có thể đăng liên kết tới nó không? –

+0

@JohnSaunders - Hans Passant cũng cho biết có một lỗi, có nghĩa là có một lỗi, liên kết với vé sẽ không chứng minh bất cứ điều gì. –

+0

Chúng tôi không có Kết nối, chỉ cần mở một vé hỗ trợ một lần .. Có vẻ như Hans đã cung cấp chi tiết về bản sửa lỗi nào dưới đây .. – XeroxDucati