2013-02-28 29 views
5

Chúng tôi có một ứng dụng WinForms AnyCPU trong đó một điều khiển thư viện nhà cung cấp thỉnh thoảng ném ngoại lệ sau đây trên hộp của người dùng 64-bit chạy nhiều màn hình:OverflowException không giải thích được đúc IntPtr đại diện màn hình phối hợp để Int32

System.OverflowException: Arithmetic operation resulted in an overflow. 
    at VendorLibraryName.VendorControl.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 

tôi đã nhìn vào xử lý WndProc thư viện nhà cung cấp kiểm soát, và các bit duy nhất của mã mà có vẻ như nó có thể tạo ra một tràn là thế này (ý kiến ​​của tôi - điều này được dịch ngược):

switch (msg) 
{ 
    case 132: // NCHITTEST 
    case 672: // NCMOUSEHOVER 

    // Technically dangerous: convert IntPtr to Int32 in a 64-bit process. 
    // However, note that for these message codes, 
    // LParam represents a "packed" x and y screen-coordinate. 
    // Given my understanding of how this packing occurs, I can't think 
    // of how to construct an LParam such that it would overflow an Int32. 
    SomeMethod(x: (int)m.LParam & 65535, y: (int)m.LParam >> 16); 

    // More code... 

đây là IL thực tế cho các chuyển đổi và bit-twiddlin g:

IL_0092: ldarg.1 
IL_0093: call instance native int [System.Windows.Forms]System.Windows.Forms.Message::get_LParam() 

// As far as I can tell, this is the only instruction on which overflow could occur 
IL_0098: call int32 [mscorlib]System.IntPtr::op_Explicit(native int) 

IL_009d: ldc.i4 65535 
IL_00a2: and 
IL_00a3: ldarg.1 

// Same thing here... 
IL_00a4: call instance native int [System.Windows.Forms]System.Windows.Forms.Message::get_LParam() 
IL_00a9: call int32 [mscorlib]System.IntPtr::op_Explicit(native int) 

IL_00ae: ldc.i4.s 16 
IL_00b0: shr 

Rõ ràng, quy trình này có vẻ dễ bị các vấn đề tràn khi có chuyển đổi Message.LParam (IntPtr) sang Int32 trong quy trình 64 bit. Trong thực tế, thói quen này là sai ở chỗ nó không đối phó với các tọa độ âm một cách chính xác - có vẻ như một cổng không chính xác của các cửa sổ GET_X_LPARAM và GET_Y_PARAM macro đến C#.

Tuy nhiên, tôi không thể xem LParam có thể được xây dựng như thế nào cho NCHITTEST/NCMOUSEHOVER, trong thực tế, sẽ tràn phạm vi Int32. (I nghĩ rằng 16 bit thấp hơn bao gồm đã ký phối hợp 16 bit X và các bit còn lại bao gồm toạ độ Y 16-bit mở rộng. Hãy sửa tôi nếu sai vì đây có thể là một sự hiểu lầm quan trọng) .

Tôi không thể tạo lại ngoại lệ trên hộp dev của mình với nhiều cấu hình màn hình và vị trí cửa sổ khác nhau.

Điều phối màn hình nào thực sự có thể dẫn đến tràn ở đây? Hoặc là có cách nào khác khối này có thể dẫn đến một tràn?

+0

Thậm chí nếu bạn don' t tìm hiểu lý do tại sao các thông số tràn, chuyển đổi mù của IntPtr để Int32 rõ ràng là một lỗi trong thư viện. Microsoft chỉ đảm bảo những gì được ghi lại, nó không đảm bảo bất cứ điều gì về các bit không có giấy tờ. Bạn nên liên hệ với nhà cung cấp để sửa lỗi –

+0

@Simon: Đúng vậy. Nhà cung cấp này đã không được nhắc nhở với các sửa lỗi trong quá khứ mặc dù; vì vậy tôi hy vọng rằng sẽ mất thời gian. Trong khi đó, tôi muốn xác định những gì * chính xác * kích hoạt ngoại lệ trong sản xuất để chúng tôi có thể hướng dẫn người dùng cách làm việc xung quanh nó. Trung hạn, chúng tôi có thể sẽ đưa ra một số cách giải quyết trong mã ứng dụng của mình. Đầu tiên, tôi cần một repro! – Ani

+0

Hmmm ... có thể nó có thể liên quan đến kích thước màn hình ảo không? Chỉ có một điều tôi có thể nghĩ rằng điều đó sẽ tràn đúng ... – JerKimball

Trả lời

0

Tôi nghĩ rằng vấn đề chính của bạn nằm trong "nhiều màn hình". Multiple monitors can lead to negative coordinates

Từ MSDN:

Quan trọng: Không sử dụng các macro LOWORD hoặc HIWORD để trích xuất x- và tọa độ y- của vị trí con trỏ vì các macro trở kết quả không chính xác trên hệ thống với nhiều màn hình. Hệ thống có nhiều màn hình có thể có tọa độ x và y âm và LOWORD và HIWORD coi tọa độ là số lượng không dấu.

Vì số CLR được ký được thể hiện bằng cách sử dụng 2-complements notation, số âm được biểu thị bằng số không dấu "lớn" (số có bit quan trọng nhất là '1'); ví dụ, -1 là 1111 .... 1. Do đó, tràn khi đúc thành một số nguyên 32 bit (đã ký).

EDIT: (tuyên bố từ chối trách nhiệm: Tôi không có nhiều màn hình, vì vậy một số phỏng đoán được áp dụng) Tóm lại: phỏng đoán của tôi là bạn phải tạo tọa độ âm âm.

Giả sử tọa độ là (x: -1, y: -1)

số Như ngắn: x: 0xFFFF, y: 0xFFFF

đóng gói trong một số 32-bit: 0xFFFF FFFF

Bây giờ, đây là nơi phỏng đoán có liên quan: không có phần mở rộng dấu hiệu để IntPtr (bạn có thể thử nó với trình gỡ rối? Bạn sẽ cần một y phủ định). Do đó, nó sẽ trở thành:

0x0000 0000 FFFF FFFF 

Hoặc 4294967295 Số nào quá lớn để truyền tới Int32.

Nói chung, bất kỳ Y âm tọa độ sẽ theo hình thức

000.(32 Zeros)..001 ...(other 31 digits) .. 0 

và sẽ mang lại thành vấn đề (có bạn đã cố gắng xếp các màn hình chồng lên nhau?)

+0

Tôi biết về lỗi tọa độ âm trong quy trình của nhà cung cấp (như tôi đã đề cập). Tuy nhiên, không có thử nghiệm nào của tôi với các tọa độ âm (cả x và y) gây ra bất kỳ ngoại lệ tràn - chúng gây ra sự giải thích không chính xác các tọa độ. Bạn có thể cho tôi bất kỳ tọa độ tiêu cực mẫu nào có thể gây ra lỗi không? – Ani

+0

Tôi nghĩ rằng lỗi trong thư viện đang chuyển thành int trước khi áp dụng mặt nạ/ca. Hãy để tôi nghĩ rằng nếu có thể có một số trường hợp cực đoan mà tọa độ có thể dẫn đến số lượng rất lớn .. hoặc nếu nó có thể được kết luận rằng không có giá trị có thể gây ra một tràn, và bạn phải tìm ở nơi khác ... –

+0

Tôi đã thêm (giáo dục của tôi)) đoán, và cung cấp một ví dụ –

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