有没有人stackalloc在C#编程时实际使用过?我知道它的作用是什么,但它出现在我的代码中的唯一一次是偶然的,因为Intellisense在我开始输入时建议它static,例如.
虽然它与使用场景无关,但stackalloc我实际上在我的应用程序中做了大量的遗留互操作,因此我偶尔会使用unsafe代码.但是,我通常会找到unsafe完全避免的方法.
而且由于.Net中单个线程的堆栈大小约为1Mb(如果我错了,请纠正我),我使用时更加保留stackalloc.
是否有一些实际案例可以说:"这对我来说是不正确的数据和处理不安全和使用stackalloc"?
下面的“修复”让我很困惑;这里的场景是根据大小有条件地决定是使用堆栈还是租用缓冲区 - 这是一个非常利基但有时必要的优化,但是:使用“明显”的实现(数字 3,推迟明确的分配,直到我们真正想要分配它),编译器抱怨 CS8353:
不能在此上下文中使用类型为“Span<int>”的 stackalloc 表达式的结果,因为它可能会暴露在包含方法之外
简短的再现(完整的再现如下)是:
// take your pick of:
// Span<int> s = stackalloc[0]; // works
// Span<int> s = default; // fails
// Span<int> s; // fails
if (condition)
{ // CS8353 happens here
s = stackalloc int[size];
}
else
{
s = // some other expression
}
// use s here
Run Code Online (Sandbox Code Playgroud)
我在这里唯一能想到的是,编译器确实在标记stackalloc正在逃避发生的上下文stackalloc,并且挥舞着一个标志说“我无法证明这在方法后面是否安全” ,但是通过stackalloc[0]在开始时使用 ,我们将“危险”上下文范围推得更高,现在编译器很高兴它永远不会逃脱“危险”范围(即它从未真正离开方法,因为我们声明在顶部范围)。这种理解是否正确,就可以证明的内容而言,这只是编译器的限制?
什么是真正有趣的(对我)是,= stackalloc[0]是根本无操作无论如何,这意味着至少在编译的形式工作1号= …
我正在重构我的库,以Span<T>尽可能避免堆分配,但是由于我也针对较旧的框架,因此我也在实现一些通用的后备解决方案。但是现在我发现了一个奇怪的问题,我不确定是在.NET Core 3中发现了错误还是在做违法的事情。
问题:
// This returns 1 as expected but cannot be used in older frameworks:
private static uint ReinterpretNew()
{
Span<byte> bytes = stackalloc byte[4];
bytes[0] = 1; // FillBytes(bytes);
// returning bytes as uint:
return Unsafe.As<byte, uint>(ref bytes.GetPinnableReference());
}
// This returns garbage in .NET Core 3.0 with release build:
private static unsafe uint ReinterpretOld()
{
byte* bytes = stackalloc byte[4];
bytes[0] = 1; // FillBytes(bytes);
// returning bytes as uint:
return *(uint*)bytes;
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,它 …
该stackalloc关键字提供哪些功能?何时以及为什么要使用它?
我对stackalloc操作员的功能有几个问题.
它是如何实际分配的?我认为它的确如下:
void* stackalloc(int sizeInBytes)
{
void* p = StackPointer (esp);
StackPointer += sizeInBytes;
if(StackPointer exceeds stack size)
throw new StackOverflowException(...);
return p;
}
Run Code Online (Sandbox Code Playgroud)
但我做了一些测试,我不确定它是如何工作的.我们无法确切知道它的作用以及它是如何做到的,但我想知道基础知识.
我认为堆栈分配(好吧,我确实相信它)比堆分配快.那么为什么这个例子:
class Program
{
static void Main(string[] args)
{
Stopwatch sw1 = new Stopwatch();
sw1.Start();
StackAllocation();
Console.WriteLine(sw1.ElapsedTicks);
Stopwatch sw2 = new Stopwatch();
sw2.Start();
HeapAllocation();
Console.WriteLine(sw2.ElapsedTicks);
}
static unsafe void StackAllocation()
{
for (int i = 0; i < 100; i++)
{
int* p = stackalloc int[100];
}
}
static void HeapAllocation() …Run Code Online (Sandbox Code Playgroud)如果我stackalloc在C#中分配内存,那个内存是否已初始化(带0)?
文档没有提到这一点,只说明保留了正确的金额.
在我的测试中,这样的内存默认为0,但这并不意味着它得到了保证.
如果stackalloc与参考类型一起使用如下
var arr = stackalloc string[100];
Run Code Online (Sandbox Code Playgroud)
有一个错误
不能获取地址,获取大小,或声明指向托管类型的指针('string')
为什么会这样?为什么CLR不能声明指向托管类型的指针?
我想使用 Span 和 stackalloc 分配一个结构数组并将其传递给互操作调用。是否可以在不安全的情况下从 Span 检索指针 (IntPtr)?
来自stackalloc的C#参考:
stackalloc的使用自动启用公共语言运行库(CLR)中的缓冲区溢出检测功能.如果检测到缓冲区溢出,则会尽快终止该过程,以最大程度地降低恶意代码执行的可能性.
具体来说,为.NET实现了什么样的保护机制?
它还会检测缓冲区欠载吗?对已知攻击的保护力较弱?
对于上下文,例如对于MS C++编译器,此处提供了以下信息:
Windows ISV软件安全防御:
堆栈缓冲区溢出检测功能已引入Visual Studio .NET 2002中的C/C++编译器,并在后续版本中进行了更新./ GS是一个编译器开关,指示编译器添加启动代码,函数epilog和prolog代码,以生成和检查放置在函数堆栈中的随机数.
请注意,Visual C++ 2005(及更高版本)也会重新排序堆栈上的数据,以便更难以预测地破坏该数据.示例包括:
•将缓冲区移动到比非缓冲区更高的内存.此步骤可以帮助保护驻留在堆栈上的函数指针.
•在运行时将指针和缓冲区参数移动到较低的内存,以缓解各种缓冲区溢出攻击.
我将一些较旧的高速 C++ 代码移植到 C#,现有代码使用了这样的基于指针的双间接模式(此处以 C# 语法编写),使用堆栈作为高效的临时存储:
\npublic struct Source {\n public byte* Start;\n public int Count;\n}\n\npublic struct SourceSet {\n public Source* Start;\n public int Count;\n}\n\nSource* sources = stackalloc Source[n*k];\nSourceSet* sourceSets = stackalloc SourceSet[n];\nRun Code Online (Sandbox Code Playgroud)\nsources它用数据段的集合填充,并用每组中有sourceSets多少个来填充 。Source
该代码工作正常,但理想情况下,我想将其转换为不再使用指针和unsafe\xe2\x80\x94 来代替使用像这样的内存安全的东西,其中每个都由一个源SourceSet填充:.Slice()
public struct Source {\n public int Start;\n public int Count;\n}\n\nSpan<Source> sources = stackalloc Source[n*k];\nSpan<Span<Source>> sourceSets = stackalloc Span<Source>[n];\nRun Code Online (Sandbox Code Playgroud)\n但我不能这么写,因为Span<Span<T>>C# 中不能存在 \xe2\x80\x94Span<T>是 a ref struct,因此不能用作 …