c# - 使用 AcquirePointer 时处理 SafeMemoryMappedViewHandle 的正确方法是什么?
问题描述
我有一些代码可以打开一个内存映射文件并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
if_isDisposed
为真,以避免 UAF 错误和内存损坏。
当从 a 中暴露不安全的指针时,以下哪一个是正确的处置模式SafeMemoryMappedViewHandle
?此外,是否值得Memory
在处置期间将该字段设置为空?
解决方案
推荐阅读
- github-pages - Github Actions 克隆无法读取用户名
- javascript - 如何过滤作为对象数组中对象属性的电子邮件域?
- swiftui - TabView 中的 SwiftUI 导航标题
- python - 谁能推荐如何解决这个错误?
- python - XGBoost 损失不随 HyperOpt 改变
- python - 从 Python 客户端发送的 GRPC 请求没有被 Golang 服务器正确接收
- sonarqube - 声纳扫描仪可以只扫描`git ls-files`中的文件吗?
- javascript - js 日志绑定对象
- merge - TFS/Azure 分支和合并策略
- c++ - 在使用 Xcode 13 在 iOS 15 上编译 Cronet 时,shrink_to_fit() 的“未定义符号”