Frage

Hintergrund

Wir haben einen Code verwendet, der wörtlich von Joe Duffys "Concurrent Programing on Windows" (Seite 149) in Produktion über ein Jahr kopiert hat. Der Code (unten) wird in unserer ASP.NET -Webanwendung verwendet, um zu untersuchen, wenn genügend Stapelraum vorhanden ist. Unsere Website ermöglicht es Benutzern, ihre eigenen Webseiten zu entführen und die Logik in einer einfachen proprietry Scripting -Sprache zu steuern. Ein Benutzer kann etwas Bösees einstellen und eine Stackoverflow -Ausnahme verursachen. Daher verwenden wir das Code -Beispiel von Duffy, um die Ausführung des fehlerhaften Skripts vor dem Vorgang vor dem Skript zu stoppen Die ungerichtbare Stackoverflow -Ausnahme nimmt die gesamte IIS -Apppool ab. Das hat sehr gut funktioniert.

Das Problem

Plötzlich heute Nachmittag haben unsere Protokolle mit Systems gefüllt. OverflowException -Fehler. Wir haben auf jeder Anfrage an diesen Server die gleiche Ausnahme erhalten. Ein Swift IIS Reset heilte das Problem.

Ausnahmetyp: System.Overflowexception

Ausnahmemeldung: Die arithmetische Operation führte zu einem Überlauf.

Stack Trace: at system.intptr..ctor (int64 value) at liqueHtmlflowManager.stackManagement.CheckForfUellabyStack (uint64 Bytes) in C: svn liquidhtml Trunk LiquidHtmlflowManager stackmanagement.cs: Line 47 47

Der Code:

public static class StackManagement
{
    [StructLayout(LayoutKind.Sequential)]
    struct MEMORY_BASIC_INFORMATION
    {
        public uint BaseAddress;
        public uint AllocationBase;
        public uint AllocationProtect;
        public uint RegionSize;
        public uint State;
        public uint Protect;
        public uint Type;
    };

    //We are conservative here. We assume that the platform needs a 
    //whole 16 pages to respond to stack overflow (using an X86/X64
    //page-size, not IA64). That's 64KB, which means that for very
    //small stacks (e.g. 128kb) we'll fail a lot of stack checks (say in asp.net)
    //incorrectly.
    private const long STACK_RESERVED_SPACE = 4096 * 16;

    /// <summary>
    /// Checks to see if there is at least "bytes" bytes free on the stack.
    /// </summary>
    /// <param name="bytes">Number of Free bytes in stack we need.</param>
    /// <returns>If true then there is suffient space.</returns>
    public unsafe static bool CheckForSufficientStack(ulong bytes)
    {
        MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
        //We subtract one page for our request. VirtualQuery rounds up
        //to the next page. But the stack grows down. If we're on the 
        //first page (last page in the VirtualAlloc), we'll be moved to
        //the next page which is off the stack! Note this doesn't work
        //right for IA64 due to bigger pages.
        IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);

        //Query for the current stack allocation information.
        VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

        //If the current address minus the base (remember: the stack
        //grows downward in the address space) is greater than the 
        //number of bytes requested plus the unreserved space at the end,
        //the request has succeeded.
        System.Diagnostics.Debug.WriteLine(String.Format("CurrentAddr = {0}, stackInfo.AllocationBase = {1}. Space left = {2} bytes.", (uint)currentAddr.ToInt64(),
            stackInfo.AllocationBase,
            ((uint)currentAddr.ToInt64() - stackInfo.AllocationBase)));

        return ((uint)currentAddr.ToInt64() - stackInfo.AllocationBase) > (bytes + STACK_RESERVED_SPACE);
    }

    [DllImport("kernel32.dll")]
    private static extern int VirtualQuery(IntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
}

Hinweis: Zeile 47 ist dieser

IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);

Die Frage:

Welcher Teil des Codes überläuft, ist es der Guss vom Zeiger auf die Uint, die "- 4096" -Operation oder die Besetzung zum INT64?

Irgendwelche Ideen, wie man das robuster macht?

Einige weitere Informationen:

Das Betriebssystem ist 64 -Bit -Windows -Server 2008 und wird IIS7 mit einer Intel Zeon (x86) -CPU ausgeführt.

Der Parameter, der an die Funktion untersuchten, ist ausreichend Stack -Funktion, lautet:

private const Int32 _minimumStackSpaceLimit = 48 * 1024;

Bearbeiten: Danke für die Antwort. Ich habe den Code aktualisiert, um die Abgüsse zu entfernen und Variablen der Zeigergröße zu verwenden, damit er sowohl in 32 als auch in 64 Bit funktioniert. Hier will es jemand anderes wollen:

public static class StackManagement
    {
        [StructLayout(LayoutKind.Sequential)]
        struct MEMORY_BASIC_INFORMATION
        {
            public UIntPtr BaseAddress;
            public UIntPtr AllocationBase;
            public uint AllocationProtect;
            public UIntPtr RegionSize;
            public uint State;
            public uint Protect;
            public uint Type;
        };

        private const long STACK_RESERVED_SPACE = 4096 * 16;

        public unsafe static bool CheckForSufficientStack(UInt64 bytes)
        {
            MEMORY_BASIC_INFORMATION stackInfo = new MEMORY_BASIC_INFORMATION();
            UIntPtr currentAddr = new UIntPtr(&stackInfo);
            VirtualQuery(currentAddr, ref stackInfo, sizeof(MEMORY_BASIC_INFORMATION));

            UInt64 stackBytesLeft = currentAddr.ToUInt64() - stackInfo.AllocationBase.ToUInt64();

            System.Diagnostics.Debug.WriteLine(String.Format("CurrentAddr = {0}, stackInfo.AllocationBase = {1}. Space left = {2} bytes.", 
                currentAddr,
                stackInfo.AllocationBase,
                stackBytesLeft));

            return stackBytesLeft > (bytes + STACK_RESERVED_SPACE);
        }

        [DllImport("kernel32.dll")]
        private static extern int VirtualQuery(UIntPtr lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, int dwLength);
    }
War es hilfreich?

Lösung

Die Besetzung ist einfach falsch. Die Adresse von Stackinfo ist ein 64-Bit-Wert. Sie können das nicht an eine Uint geben, ohne die Überflutung zu riskieren. Es macht auch keinen Sinn, 4096 zu subtrahieren, VirtualQuery () wird die Basisadresse ohnehin finden. Fix:

 IntPtr currentAddr = new IntPtr(&stackInfo);

Duffys Code kann nur für 32-Bit-Code funktionieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top