Когда безопасно вернуть Span <T>, инициализированный из переменной / буфера, выделенных стеком? - PullRequest
0 голосов
/ 08 октября 2018

Являются ли следующие 2 примера возврата Span<byte>Span<T> в более общем смысле) безопасными в том смысле, что при возврате метода область памяти, на которую возвращенный экземпляр Span<T> указывает, все еще содержит значимые данные:

  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 return и ref влияет на это (если их вообще есть)?
  • Имеет ли значение встраивание?

1 Ответ

0 голосов
/ 08 октября 2018

Это небезопасно, поскольку память, выделенная с помощью stackalloc, больше не гарантируется, что будет доступна после выхода из функции.

Во всех случаях, когда это компилируется, вы использовали небезопасные средства для отмены предупреждений.Используя небезопасный код, вы можете делать все, что захотите.Например, вы можете вернуть указатель на int в стеке (int x = 0; return &x;), который столь же небезопасен.

Это не может быть каким-либо другим способом, потому что язык или среда выполнения не могут отследить время жизничерез эти небезопасные объекты.Даже если бы он мог отследить его, он бы разрушил преимущества производительности stackalloc.stackalloc память быстрая, потому что известно, что она освобождается при выходе из функции.

...