Как правильно избавиться от SafeMemoryMappedViewHandle при использовании AcquirePointer? - PullRequest
0 голосов
/ 30 сентября 2018

У меня есть код, который открывает файл сопоставления памяти и выставляет ReadOnlySlice<T> для ряда операций синтаксического анализа.Упрощенный код класса ниже:

public MemoryMappedViewAccessor Accessor { get; }
public SafeMemoryMappedViewHandle Handle { get; }
public byte* Memory;
private long _size;

public Parser(MemoryMappedFile mappedFile, long offset, long size)
{
    _size = size;
    Accessor = mappedFile.CreateViewAccessor(offset, _size, MemoryMappedFileAccess.Read);
    Handle = Accessor.SafeMemoryMappedViewHandle;
    unsafe
    {
        Handle.AcquirePointer(ref Memory);
    }
}

public ReadOnlySlice<T> GetSpan<T>(int offset, int size)
{
    return new ReadOnlySpan<T>(chunk.Memory, _size).Slice(offset, size);
}

/* other functions exposing various Slice<T> over this */

Очевидно, это требует от моего класса реализации IDisposable, но я не уверен, где находится граница между небезопасными и безопасными ресурсами.Одна ссылка , которую я обнаружил , говорит, что SafeMemoryMappedViewHandle является управляемым ресурсом и должен быть утилизирован как таковой, но в нем не упоминается, как это меняется с ReleasePointer, или нужно ли вообще вызывать ReleasePointer доDispose.

На мой взгляд, следующие два шаблона Dispose являются моими вариантами:

Вариант 1 - Рассматривать все как управляемое

private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_isDisposed)
    {
        if (disposing)
        {
            Accessor.Dispose();
            Handle.ReleasePointer(); // is this even needed?
            Handle.Dispose();
        }

        _isDisposed = true;
    }
}

public void Dispose()
{
    Dispose(true);
}

Вариант 2 - Рассматривать освобождение указателя как неуправляемое

private bool _isDisposed = false;

protected virtual void Dispose(bool disposing)
{
    if (!_isDisposed)
    {
        if (disposing)
        {
            Accessor.Dispose();
        }

        Handle.ReleasePointer();
        Handle.Dispose();

        _isDisposed = true;
    }
}

~FileChunk()
{
    Dispose(false);
}

public void Dispose()
{
    Dispose(true);
    GC.SuppressFinalize(this);
}

В обоих этих случаях я бы добавил проверку в мою логику синтаксического анализа для выдачи ObjectDisposedException, если _isDisposed верно, чтобы избежать ошибок UAF и повреждения памяти.

Какой из них является правильным шаблоном удаления, когда небезопасные указатели выставляются с SafeMemoryMappedViewHandle?Кроме того, стоит ли устанавливать для поля Memory значение null во время утилизации?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...