2016-02-10 68 views
5

在夜间构建计算机上构建的应用程序在Windows Server 2012上无法正常工作,但在其他桌面上运行正常。在Windows Server 2012上构建的二进制文件失败Windows Server 2012上的文件

该例外 “试图读取或写入受保护的内存,这通常表示其他内存已损坏。”被抛出。

当我使用WindowsServer2012机器上的远程调试和构建机器进行调试时,发现这个异常是在代码中kernel32调用HeapSize的地方引发的。这里是如何HeapSize是进口的,并呼吁:

[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; 
} 

。这被称作不安全类的构造函数的一部分:

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

上有什么可以丢失,如何解决这个任何线索?

这是我在WinDbg中看到:

This is what I see in Windbg

事件日志显示:

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

您是否使用PInvoke来调用HeapSize?你能显示方法声明吗? (另外,在所有的机器相同的架构,即86 VS 64?) – stuartd

+1

采取崩溃转储,它与[WinDbg的+ SOS](https://blogs.msdn.microsoft.com/kaevans/2011/04捅/ 11/intro-to-windbg-for-net-developers /) –

+0

是的配置是相同的 - 两台机器都是x64,代码是用x64配置的。 的代码是: [的DllImport( “KERNEL32”)] 静态外部INT HEAPSIZE(INT hHeap,整数标记,无效*块); //返回一个内存块的大小。 公共静态INT一下SizeOf(无效*块) { INT结果= HEAPSIZE(pH值,0,块); if(result == -1)throw new InvalidOperationException(); 返回结果; } – NVK

回答

2

你写的代码不应该是工作过。

HeapSize返回堆的大小,例如,通过调用HeapAlloc分配的东西。提供给HeapSize指针必须通过调用HeapAlloc返回的指针:

lpMem [IN]

的指针存储器块的大小的功能将得到。这是HeapAlloc或HeapReAlloc函数返回的指针。

你打电话HeapSize,而是提供了一个指针,可能是堆内的任何地方;或者没有在堆都:

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

不仅将Marshal.StringToHGlobalAnsi()堆中某处返回一个指针,而不是指向堆本身,你甚至不知道堆指针被分配来自,因为该进程可能会分配多个堆。

所有这些都没有关系,因为看起来你对这个函数的目的有一个基本的误解 - 你似乎正在使用它来检索堆内分配的大小。由Marshal.StringToHGlobalAnsi()返回的内存未通过调用HeapAlloc()分配(因为它不是堆!),它通过调用AllocHGlobal进行分配。由它分配的内存通过调用Marshal.FreeHGlobal()释放:

Marshal.StringToHGlobal()的文档:

因为这种方法分配的字符串所需的非托管内存,总是通过调用FreeHGlobal释放内存。

Marshal方法无关HeapAllocHeapSize或相关功能。

如果您确实想知道Marshal.StringToHGlobal()返回的指针的内存分配大小,您可以深入探究source of the the Marshal class并发现它使用win32函数LocalAlloc。恰巧LocalAlloc有一个姊妹函数LocalSize,它确实可以用来查找分配的大小。

但是,也不能保证,这样做将在今后的工作,因为.NET Framework不保证它会继续使用LocalAlloc。如果他们更改内部LocalSize可能会停止工作。

...

所有这一切说:

我不认为任何这就是你的意思是摆在首位

做再次在你的代码看:

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

你试图找到返回给你的ANSI字符串的长度。

HeapSizeLocalSize的全部业务是完全不相关的。

如果你只是想找到一个“ANSI”字符串的长度,你只需要实现一个愚蠢的简单的字符串长度,或使用任何的实现已经在你身边。

下面的程序使用Marshal.StringToHGlobal(),并打印:

字符串: '你好';长度: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; 
    } 
相关问题