gpt4 book ai didi

c# - 算术运算导致不安全 C# 中的溢出

转载 作者:太空狗 更新时间:2023-10-30 00:57:24 25 4
gpt4 key购买 nike

背景

一年多来,我们一直在生产中使用从 Joe Duffy 的“Windows 上的并发编程”(第 149 页)逐字复制的一些代码。代码(如下)用于我们的 Asp.Net Web 应用程序以探测是否有足够的堆栈空间。我们的站点允许用户使用简单的专有脚本语言编写他们自己的网页和控制逻辑的脚本——用户可能编写一些讨厌的脚本并导致计算器异常,因此我们使用 Duffy 的代码示例来停止错误脚本的执行无法捕获的 StackOverflow 异常会关闭整个 IIS AppPool。这一直运作良好。

问题

今天下午突然间我们的日志中充满了 System.OverflowException 错误。我们对该服务器的每个请求都有相同的异常。快速重置 IIS 解决了这个问题。

异常类型:系统溢出异常

异常信息:算术运算导致溢出。

堆栈跟踪: 在 System.IntPtr..ctor(Int64 值) 在 C:\SVN\LiquidHtml\Trunk\LiquidHtmlFlowManager\StackManagement.cs 中的 LiquidHtmlFlowManager.StackManagement.CheckForSufficientStack(UInt64 字节):第 47 行

代码:

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

注意:第47行就是这一行

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

问题:

代码的哪一部分溢出了,是从指针到 uint 的转换,“- 4096”操作,还是到 Int64 的转换?

有什么想法可以使它更健壮吗?

更多信息:

操作系统是 64 位 Windows Server 2008,运行 IIS7 和 Intel Zeon (x86) CPU。

传递给 CheckForSufficientStack 函数的参数是:

private const Int32 _minimumStackSpaceLimit = 48 * 1024;

编辑:感谢您的回答。我更新了代码以删除强制转换并使用指针大小的变量,以便它在 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);
}

最佳答案

类型转换错了。 stackinfo 的地址是一个 64 位值。您不能在不冒 OverflowException 风险的情况下将其强制转换为 uint。减去 4096 也没有意义,VirtualQuery() 无论如何都会找到基地址。修复:

 IntPtr currentAddr = new IntPtr(&stackInfo);

Duffy 的代码只能用于 32 位代码。

关于c# - 算术运算导致不安全 C# 中的溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5303227/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com