【问题标题】:When is it Safe to Return Span<T> Initialized from Stack-Allocated Variable / Buffer?返回从堆栈分配的变量/缓冲区初始化的 Span<T> 何时安全?
【发布时间】:2019-03-12 20:11:40
【问题描述】:

以下2个返回Span&lt;byte&gt;(以及更普遍的Span&lt;T&gt;)的例子在某种意义上是安全的,当方法返回时,Span&lt;T&gt;的返回实例指向的内存位置仍然包含有意义的数据:

  static class Example {

    public static void Main() {
      var n = 0x0102030405060708U;
      var n_bytes_as_span_of_byte = n.ToBytesExtension();
      var n2 = 0x8899aabbccddeeffU; // <- will this "overwrite" span-contents above?
      //Do something with both n2 and n_bytes_as_span_of_byte...

      //Do something with StackAllocExtensions
    }


    [MethodImpl(MethodImplOptions.AggressiveInlining)]
   public static unsafe Span<byte> ToBytesExtension(
      this ulong num // <- Will making it 'ref' make any difference: 'this ref ulong num'?
    ) => new Span<byte>( // <- Will returning it by 'ref' make any difference: ... => ref ...?
      Unsafe.AsPointer(ref num) // <- What if we use '&num' instead of 'Unsafe.AsPointer(ref num)'
      , sizeof(ulong));


      [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static Span<byte> StackAllocExtensionThatDoesNotCompile(ulong someArg) {
      Span<byte> span = stackalloc byte[16];
      //Do something with span and someArg...

      return span; // <- Does not work: Cannot use local 'span' in this context because it may expose referenced variables outside of their declaration scope.
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static unsafe Span<byte> StackAllocExtensionThatCompiles(ulong someArg) {
      var byte_pointer = stackalloc byte[16];
      //Do something with span and someArg...

      return new Span<byte>(byte_pointer, 16); // <- But isn't this the same as above? I.e. "exposes referenced variables outside of their declaration scope"?
    }

  }

还有:

  • 使用ref returnref 参数如何影响这一点(如果有的话)?
  • 内联有什么不同吗?

【问题讨论】:

    标签: .net memory stack c#-7.3


    【解决方案1】:

    这是不安全的,因为使用 stackalloc 分配的内存在函数退出后不再保证可用。

    在编译的所有情况下,您都使用了不安全的工具来覆盖警告。使用不安全的代码,你可以做任何你想做的事情。例如,您可以返回指向堆栈上的 int 的指针 (int x = 0; return &amp;x;),这同样不安全。

    不可能有任何其他方式,因为语言或运行时无法通过这些不安全的设施跟踪生命周期。即使它可以跟踪它,它也会破坏stackalloc 的性能优势。 stackalloc 内存很快,因为已知它会在函数退出时被释放。

    【讨论】:

      猜你喜欢
      • 2015-11-15
      • 2012-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 2011-12-24
      相关资源
      最近更新 更多