2016-02-10 17 views
5

Ứng dụng được xây dựng trên máy xây dựng hàng đêm không hoạt động trên Windows Server 2012 nhưng hoạt động tốt trên các máy tính để bàn khác.Các tệp nhị phân được xây dựng trên Windows 7 không thành công trên Windows Server 2012

Ngoại lệ loại "Đã cố gắng đọc hoặc ghi bộ nhớ được bảo vệ. Đây thường là dấu hiệu cho thấy bộ nhớ khác bị hỏng". được ném.

Khi tôi gỡ lỗi bằng cách sử dụng gỡ lỗi từ xa trên máy WindowsServer2012 và máy xây dựng, tôi thấy rằng ngoại lệ này được ném tại một nơi mà kernel32 gọi HeapSize được thực hiện trong mã. Dưới đây là làm thế nào HeapSize được nhập khẩu và được gọi là:

[DllImport("kernel32")] 
static extern int HeapSize(int hHeap, int flags, void* block); 
// Returns the size of a memory block. 

public static int SizeOf(void* block) 
{ 
    int result = HeapSize(ph, 0, block); 
    if (result == -1) throw new InvalidOperationException(); 
    return result; 
} 

này được gọi là một phần của nhà xây dựng một lớp học không an toàn của:

public UnManagedBuffer(StringBuilder sb) 
    { 
     PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
     Size = UnManagedMemory.SizeOf(PtrStart); 
     PtrWriteNextValue = PtrStart + Size - 1; 
     PtrReturnNextValue = PtrStart; 
    } 

Bất kỳ manh mối về những gì có thể thiếu và làm thế nào để sửa lỗi này?

Đây là những gì tôi thấy trong Windbg:

This is what I see in Windbg

EventLog cho thấy:

Log Name:  Application 
    Source:  .NET Runtime 
    Level:   Error 
    Keywords:  Classic 
    Description: 
Application: TestEngine.exe 
Framework Version: v4.0.30319 
Description: The process was terminated due to an unhandled exception. 
Exception Info: System.AccessViolationException 
    at Core.Utils.UnManagedMemory.HeapSize(Int32, Int32, Void*) 
    at Core.Utils.UnManagedMemory.SizeOf(Void*) 
    at Core.Utils.UnManagedBuffer..ctor</Event> 

Faulting application name: TestEngine.exe, version: 1.0.0.0, time stamp: 0x56b532bb 
Faulting module name: ntdll.dll, version: 6.3.9600.18185, time stamp: 0x5683f0c5 
Exception code: 0xc0000005 
Fault offset: 0x0000000000057306 
Faulting process id: 0x2eb8 
Faulting application start time: 0x01d164e45b12d7dd 
Faulting application path: C:\NGDLM\Lib\TestEngine.exe 
Faulting module path: C:\Windows\SYSTEM32\ntdll.dll 
Report Id: bea6eb89-d0d7-11e5-80eb-0050568cd888 
Faulting package full name: 
Faulting package-relative application ID: 
+0

Bạn đang sử dụng PInvoke để gọi HeapSize? Bạn có thể hiển thị tuyên bố phương pháp? (Ngoài ra, tất cả các máy có cùng kiến ​​trúc, tức là x86 vs x64?) – stuartd

+1

Lấy một bãi chứa sự cố, poke nó với [windbg + SOS] (https://blogs.msdn.microsoft.com/kaevans/2011/04/11/intro-to-windbg-for-net-developers /) –

+0

Có cấu hình giống nhau - cả hai máy đều là x64 và mã được cấu hình trong cấu hình x64. Mã này là: [DllImport ("kernel32")] static extern int HeapSize (int hHeap, int flags, void * block); // Trả về kích thước của khối bộ nhớ. static tĩnh int SizeOf (void * block) { int result = HeapSize (ph, 0, block); if (result == -1) ném InvalidOperationException mới(); kết quả trả về; } – NVK

Trả lời

2

Mã bạn đã viết nên không bao giờ làm việc.

HeapSize trả về kích thước của một đống, ví dụ: thứ gì đó được phân bổ bằng cách gọi HeapAlloc. Con trỏ cung cấp cho HeapSize phải là con trỏ trở lại bằng cách gọi HeapAlloc:

lpMem [trong]

Một con trỏ tới khối nhớ có kích thước hàm sẽ có được. Đây là một con trỏ được trả về bởi hàm HeapAlloc hoặc HeapReAlloc.

Bạn đang gọi điện thoại HeapSize, nhưng cung cấp một con trỏ có thể là bất cứ nơi nào trong đống đó; hay không ở chỗ đống ở tất cả:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

Không chỉ sẽ Marshal.StringToHGlobalAnsi() trả về một con trỏ ở đâu đó trong đống, và không phải là một con trỏ đến đống bản thân, bạn thậm chí không biết đống con trỏ đã được phân bổ từ, bởi vì quá trình có thể có nhiều đống phân bổ.

Tất cả điều đó không quan trọng, bởi vì dường như bạn có hiểu lầm cơ bản về mục đích của hàm này - dường như bạn đang sử dụng nó để truy xuất kích thước của phân bổ được thực hiện bên trong một đống. Bộ nhớ được trả lại bởi Marshal.StringToHGlobalAnsi() không được phân bổ bằng cách gọi HeapAlloc() (vì nó không phải là đống!), Bộ nhớ được phân bổ bằng cách gọi AllocHGlobal.Bộ nhớ được phân bổ bởi nó phải được giải thoát bằng cách gọi Marshal.FreeHGlobal():

Từ tài liệu Marshal.StringToHGlobal() 's:

Bởi vì phương pháp này phân bổ bộ nhớ không được quản lý cần thiết cho một chuỗi, luôn luôn giải phóng bộ nhớ bằng cách gọi FreeHGlobal.

Phương pháp Marshal này không liên quan gì đến HeapAlloc, HeapSize hoặc các chức năng liên quan.

Nếu bạn thực sự muốn tìm hiểu kích thước phân bổ bộ nhớ của con trỏ được trả về Marshal.StringToHGlobal(), bạn có thể khai thác thông qua source of the the Marshal class và tìm hiểu rằng nó sử dụng hàm win32 LocalAlloc. Điều đó xảy ra là LocalAlloc có hàm chị em LocalSize, thực sự có thể được sử dụng để tìm kích thước phân bổ.

Tuy nhiên, không có gì đảm bảo rằng làm như vậy sẽ hoạt động trong tương lai vì khung .Net không đảm bảo rằng nó sẽ tiếp tục sử dụng LocalAlloc. Nếu họ thay đổi nội bộ LocalSize có thể ngừng hoạt động.

...

Tất cả những gì đã nói:

Tôi không nghĩ rằng những điều này là những gì bạn có nghĩa là để làm ở nơi đầu tiên

Nhìn vào mã của bạn một lần nữa:

PtrStart = (byte*)Marshal.StringToHGlobalAnsi(sb.ToString()); 
    Size = UnManagedMemory.SizeOf(PtrStart); 
    PtrWriteNextValue = PtrStart + Size - 1; 
    PtrReturnNextValue = PtrStart; 

Bạn đang cố gắng tìm độ dài của chuỗi ansi được trả lại cho bạn.

Tất cả hoạt động kinh doanh này của HeapSize hoặc LocalSize hoàn toàn không liên quan.

Nếu bạn chỉ muốn tìm độ dài của chuỗi 'ansi', bạn chỉ cần triển khai chiều dài chuỗi đơn giản ngu ngốc hoặc sử dụng bất kỳ triển khai nào đã có sẵn cho bạn.

Chương trình sau sử dụng Marshal.StringToHGlobal(), và in:

String: 'Hello'; Dài: 5

public static void Main(string[] args) 
    { 
     IntPtr strPtr = IntPtr.Zero; 
     string str = "Hello"; 
     try 
     { 
      strPtr = Marshal.StringToHGlobalAnsi(str); 

      Console.Out.WriteLine("String: '{0}'; Length: {1}", str, AnsiStrLen(strPtr)); 
     } 
     finally 
     { 
      if(strPtr != IntPtr.Zero) 
      { 
       Marshal.FreeHGlobal(strPtr); 
      } 
     } 
    } 

    public static int AnsiStrLen(IntPtr strPtr) 
    { 
     int size = 0; 

     while(Marshal.ReadByte(strPtr) != 0) 
     { 
      size++; 
      strPtr = IntPtr.Add(strPtr, 1); 
     } 

     return size; 
    } 
Các vấn đề liên quan