Арифметическая операция привела к переполнению в небезопасном C # - PullRequest
4 голосов
/ 14 марта 2011

Фон

Более года мы использовали дословно скопированный код из "Параллельного программирования в Windows" Джо Даффи (стр. 149).Код (ниже) используется в нашем веб-приложении Asp.Net, чтобы проверить, достаточно ли места в стеке.Наш сайт позволяет пользователям создавать собственные веб-страницы и управлять логикой на простом проприетарном языке сценариев - пользователь может написать что-то неприятное и вызвать исключение stackoverflow, поэтому мы используем пример кода Duffy, чтобы остановить выполнение ошибочного сценария до того, какнеуловимое исключение StackOverflow уничтожает весь IIS AppPool.Это работало очень хорошо.

Проблема

Внезапно во второй половине дня наши журналы заполнились ошибками System.OverflowException.Мы получаем одно и то же исключение при каждом запросе к этому серверу.Быстрый сброс IIS устранил проблему.

Тип исключения: System.OverflowException

Сообщение об исключении: Арифметическая операция привела к переполнению.

Трассировка стека: в System.IntPtr..ctor (значение Int64) в LiquidHtmlFlowManager.StackManagement.CheckForSufficientStack (байты UInt64) в C: \ SVN \ LiquidHtml \ Trunk \ LiquidHtmlFlowManager \ StackManagement.cs: строка 47

Код:

* 10161017 * ПРИМЕЧАНИЕ: это строка 47
IntPtr currentAddr = new IntPtr((uint)&stackInfo - 4096);

Вопрос:

Какая часть кода переполняется, является ли она приведением от указателя к uint, "- 4096"операция или приведение к Int64?

Есть идеи, как сделать это более надежным?

Дополнительная информация:

Операционная система - 64-битная Windows Server 2008, работающаяIIS7 с процессором Intel Zeon (x86).

Параметр, переданный в функцию CheckForSufficientStack:

private const Int32 _minimumStackSpaceLimit = 48 * 1024;

EDIT: Спасибо за ответ.Я обновил код, чтобы убрать приведение и использовать переменные размера указателя, чтобы он работал как в 32, так и в 64 битах.Вот это, если кто-то еще хочет этого:

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

1 Ответ

6 голосов
/ 14 марта 2011

Состав исполнен неправильно.Адрес stackinfo является 64-битным значением.Вы не можете привести это к uint, не рискуя OverflowException.Также нет смысла вычитать 4096, VirtualQuery () все равно найдет базовый адрес.Исправление:

 IntPtr currentAddr = new IntPtr(&stackInfo);

Код Даффи может работать только для 32-битного кода.

...