2017-10-25 36 views
5

Tôi có đoạn mã CIL bị giảm sau đây.
Khi phương pháp CIL này được thực thi, một InvalidProgramException đang được ném bởi CLR:Tại sao localloc phá vỡ phương pháp CIL này?

.method assembly hidebysig specialname rtspecialname 
      instance void .ctor(class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase> styluses) cil managed 
    { 
    .locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<class System.Windows.Input.StylusDeviceBase> V_0, 
     class System.Windows.Input.StylusDeviceBase V_1) 

    ldc.i4.8 // These instructions cause CIL to break 
    conv.u  // 
    localloc // 
    pop  // 

    ldarg.0 
    newobj instance void class [mscorlib]System.Collections.Generic.List`1<class System.Windows.Input.StylusDevice>::.ctor() 
    call instance void class [mscorlib]System.Collections.ObjectModel.ReadOnlyCollection`1<class System.Windows.Input.StylusDevice>::.ctor(class [mscorlib]System.Collections.Generic.IList`1<!0>) 
    ldarg.1 
    callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<class System.Windows.Input.StylusDeviceBase>::GetEnumerator() 
    stloc.0 

    .try 
    { 
     leave.s IL_0040 
    } 
    finally 
    { 
     endfinally 
    } 

    IL_0040: ret 
    } // end of method StylusDeviceCollection::.ctor 

Câu hỏi của tôi là, tại sao là mã CIL này không hợp lệ?

Một số sự obervations:
- Nếu localloc bị xóa, mã sẽ chạy tốt. Theo hiểu biết của tôi, localloc thay thế kích thước tham số trên ngăn xếp bằng một địa chỉ, do đó, ngăn xếp vẫn được cân bằng, AFAICT.
- Nếu thử và cuối cùng các khối bị xóa, mã sẽ chạy tốt.
- Nếu khối lệnh đầu tiên chứa localloc được di chuyển đến sau khối thử cuối cùng, mã sẽ chạy tốt.

Vì vậy, nó có vẻ giống như một cái gì đó trong sự kết hợp của localloc và cố gắng cuối cùng.

Một số nền:

tôi đã đến thời điểm này sau khi InvalidProgramException bị ném cho phương pháp ban đầu, do một số thiết bị đo đạc được thực hiện tại thời gian chạy. Biện pháp của tôi để gỡ lỗi này, vì tìm ra những gì là sai với thiết bị đo đạc, là:

  • Cách tháo rời DLL bị lỗi với ildasm
  • Áp dụng mã số nhạc cụ phương pháp rơi
  • Tái tạo DLL từ sửa đổi IL với ilasm
  • Chạy lại chương trình và xác minh nó bị treo
  • Tiếp tục giảm mã IL của phương pháp đâm xuống dần, xuống kịch bản tối thiểu gây ra sự cố (và cố gắng không int bọ gậy dọc theo con đường ...)

Thật không may, peverify.exe /IL không cho biết bất kỳ lỗi nào. Tôi đã cố gắng điều khiển thông số kỹ thuật ECMA và cuốn sách Expert .NET IL của Serge Lidin, nhưng không thể tìm ra điều gì sai.

Có điều gì cơ bản tôi bị thiếu không?

Edit:

Tôi hơi cập nhật mã IL trong câu hỏi, để làm cho nó hoàn chỉnh hơn (mà không sửa đổi hướng dẫn). Khối lệnh thứ hai, bao gồm ldarg, newobj, v.v ..., được lấy từ mã làm việc - mã phương thức gốc.

Điều lạ với tôi là, bằng cách xóa localloc hoặc .try - finally, mã hoạt động - nhưng không có kiến ​​thức nào trong số này, nên thay đổi cân bằng của chồng, so với khi chúng có trong mã .

Dưới đây là đoạn mã IL decompiled vào C# với ILSpy:

internal unsafe StylusDeviceCollection(IEnumerable<StylusDeviceBase> styluses) 
{ 
    IntPtr arg_04_0 = stackalloc byte[(UIntPtr)8]; 
    base..ctor(new List<StylusDevice>()); 
    IEnumerator<StylusDeviceBase> enumerator = styluses.GetEnumerator(); 
    try 
    { 
    } 
    finally 
    { 
    } 
} 

Chỉnh sửa 2:

Nhiều quan sát:
- Lấy localloc khối mã IL, và di chuyển nó đến cùng của hàm, mã chạy tốt - vì vậy có vẻ như mã đó là của riêng nó là OK.
- Sự cố không sinh sản khi dán mã IL tương tự vào chức năng kiểm tra thế giới hello.

Tôi rất bối rối ...

Tôi muốn có một cách để có được thêm thông tin từ các InvalidProgramException. Dường như CLR không đính kèm lý do lỗi chính xác cho đối tượng ngoại lệ. Tôi cũng nghĩ về gỡ lỗi với CoreCLR debug xây dựng, nhưng Unforunately chương trình tôi gỡ lỗi không tương thích với nó ...

+1

Khi bạn mở tệp DLL đã biên dịch của mình trong ILSpy, nó có hiển thị mã bạn muốn xem không? (Có lẽ chỉ trong quan điểm IL - điều này có lẽ sẽ không dịch ngược thành C#, mặc dù tôi có thể sai.) – xxbbcc

+2

Đáng buồn thay, tôi không thể tái tạo điều này. Có phải 'ldarg.0' để' gọi' là cần thiết không? – IllidanS4

+2

Khá không rõ ràng làm thế nào peverify.exe có thể được sử dụng, nó không giống như localloc. Điều đó ldarg.0 mất cân bằng ngăn xếp, bạn đang gọi constructor mặc định của List <>. Chỉ cần xóa nó đi. –

Trả lời

2

Đáng buồn thay, có vẻ như tôi nhấn một lỗi CLR ...

Tất cả mọi thứ đang làm việc khi sử dụng di sản JIT Compiler:

set COMPLUS_useLegacyJit=1

tôi đã không thể để cô lập một khung cảnh RyuJit cụ thể mà có thể gây ra này. Tôi đã làm theo đề xuất trong bài viết này:
https://github.com/Microsoft/dotnet/blob/master/Documentation/testing-with-ryujit.md

Nhờ tất cả những người đã giúp!

+2

Bạn có thể muốn mở một vấn đề kho lưu trữ CoreCLR (chứa RyuJIT); có [một số] (https://github.com/dotnet/coreclr/search?type=Issues) cho 'localloc' rồi.'localloc' không được cho phép trong một' cuối cùng', vì vậy có thể jitter đang bối rối và không cho phép nó hoàn toàn ở đây, mặc dù nó không nằm trong khối. –

+0

@JeroenMostert cảm ơn! Tôi nghi ngờ đây có thể là trường hợp ... Tôi đang chạy trên .NET 4.6, do đó, sẽ kiểm tra xem việc này có tái tạo trên CoreCLR mới nhất hay không. Tôi nhận thấy một lỗi tương tự đã được khắc phục, vì vậy rất có thể, điều này có thể đã được khắc phục: https://github.com/dotnet/coreclr/blob/master/tests/src/JIT/Regression/VS- ia64-JIT/V1.2-M01/b10841/repro_good.il – valiano

+0

Rất thú vị! Tôi tự hỏi nguyên nhân gây ra lỗi là gì. – IllidanS4

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