简体   繁体   English

Windows 7上构建的二进制文件在Windows Server 2012上失败

[英]Binaries built on Windows 7 fails on Windows Server 2012

An application built on nightly build machine does not work on Windows Server 2012 but works fine on other desktops. 在夜间构建计算机上构建的应用程序在Windows Server 2012上不起作用,但在其他桌面上运行正常。

An exception of the kind "Attempted to read or write protected memory. This is often an indication that other memory is corrupt." “尝试读取或写入受保护的内存”的例外情况。这通常表明其他内存已损坏。 is thrown. 被扔了。

When I debug using remote debugging across the WindowsServer2012 machine and build machine, I see that this exception is thrown at a place where kernel32 call HeapSize is made in the code. 当我在WindowsServer2012机器和构建机器上使用远程调试进行调试时,我看到在代码中调用了kernel32调用HeapSize的地方抛出了这个异常。 Here is how HeapSize is imported and called : 以下是导入和调用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; 
}

This is called as part of an unsafe class's constructor: 这被称为不安全类的构造函数的一部分:

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

Any clues on what could be missing and how to fix this? 关于什么可能遗失的任何线索以及如何解决这个问题?

This is what I see in Windbg: 这就是我在Windbg中看到的:

这就是我在Windbg中看到的

EventLog shows: EventLog显示:

    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: 

The code you've written should not have ever worked. 你写的代码不应该有用。

HeapSize returns the size of a heap, eg, something allocated by calling HeapAlloc . HeapSize返回堆的大小,例如,通过调用HeapAlloc分配的内容。 The pointer provided to HeapSize must be the pointer returned by calling HeapAlloc : 提供给HeapSize的指针必须是通过调用HeapAlloc返回的指针:

lpMem [in] lpMem [in]

A pointer to the memory block whose size the function will obtain. 指向函数将获取其大小的内存块的指针。 This is a pointer returned by the HeapAlloc or HeapReAlloc function. 这是HeapAlloc或HeapReAlloc函数返回的指针。

You're calling HeapSize , but providing a pointer that could be anywhere within that heap; 您正在调用HeapSize ,但提供的指针可能位于该堆中的任何位置; or not in that heap at all: 或根本不在那堆:

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

Not only will Marshal.StringToHGlobalAnsi() return a pointer somewhere in the heap, and not a pointer to the heap itself, you don't even know which heap the pointer was allocated from, because the process could have multiple heaps allocated. Marshal.StringToHGlobalAnsi()不仅会在堆中的某处返回指针,而不是指向堆本身的指针,您甚至不知道指针分配到哪个堆,因为该进程可能分配了多个堆。

All of that doesn't matter, because it appears you have a fundamental misunderstanding of the purpose of this function - you appear to be using it to retrieve the size of an allocation made inside a heap. 所有这一切并不重要,因为看起来你对这个函数的目的有一个根本的误解 - 你似乎正在使用它来检索在堆内部进行的分配的大小。 The memory returned by Marshal.StringToHGlobalAnsi() is not allocated by calling HeapAlloc() (because it's not a heap!), it's allocated by calling AllocHGlobal . Marshal.StringToHGlobalAnsi()返回的内存不是通过调用HeapAlloc()分配的(因为它不是堆!),它是通过调用AllocHGlobal来分配的。 The memory allocated by it has to be freed by calling Marshal.FreeHGlobal() : 必须通过调用Marshal.FreeHGlobal()释放由它分配的内存:

From Marshal.StringToHGlobal() 's documentation: 来自Marshal.StringToHGlobal()的文档:

Because this method allocates the unmanaged memory required for a string, always free the memory by calling FreeHGlobal. 因为此方法分配字符串所需的非托管内存,所以始终通过调用FreeHGlobal释放内存。

This Marshal method has nothing to do with HeapAlloc , HeapSize or related functions. 这个Marshal方法与HeapAllocHeapSize或相关函数无关。

If you did actually want to find out the size of the memory allocation of the pointer returned by Marshal.StringToHGlobal() , you could dig through the source of the the Marshal class and find out that it uses the win32 function LocalAlloc . 如果你确实想要找出Marshal.StringToHGlobal()返回的指针的内存分配大小,你可以挖掘Marshal类源代码并发现它使用了win32函数LocalAlloc It so happens that LocalAlloc has a sister function LocalSize , which indeed can be used to find the size of an allocation. 碰巧LocalAlloc有一个姐妹函数LocalSize ,它确实可以用来查找分配的大小。

However, there is no guarantee that doing so will work in the future, because the .Net framework provides no guarantee that it'll continue to use LocalAlloc . 但是,无法保证这样做将来会有效,因为.Net框架无法保证它将继续使用LocalAlloc If they changed the internals LocalSize might stop working. 如果他们更改了内部, LocalSize可能会停止工作。

... ...

All of that said: 所有这些都说:

I don't think any of this is what you meant to do in the first place 我不认为这首先是你打算做的

Looking at your code again: 再看一下你的代码:

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

You're trying to find the length of the ansi string returned to you. 你试图找到返回给你的ansi字符串的长度。

All of this business of HeapSize or LocalSize is completely irrelevant. HeapSizeLocalSize所有这些业务完全无关紧要。

If you just want to find the length of an 'ansi' string, you just need to implement a stupid simple string length, or use any of the implementations already there for you. 如果你只是想找到'ansi'字符串的长度,你只需要实现一个简单的简单字符串长度,或者使用已经存在的任何实现。

The following program uses Marshal.StringToHGlobal() , and prints: 以下程序使用Marshal.StringToHGlobal() ,并打印:

String: 'Hello'; 字符串:'你好'; Length: 5 长度: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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM