将不安全可变指针转换为字符串时的堆缓冲区溢出<UInt8>



执行以下操作时,我收到地址清理器的错误:

let pointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
pointer.storeBytes(of: 77, as: UInt8.self)
pointer.advanced(by: 1).storeBytes(of: 105, as: UInt8.self)
(pointer+2).storeBytes(of: 107, as: UInt8.self)
(pointer+3).storeBytes(of: 101, as: UInt8.self)
let typedPointer = pointer.bindMemory(to: UInt8.self, capacity: 4)

let readableData = String(cString: typedPointer)

我得到堆缓冲区溢出,但我不明白为什么。在我的实际代码中,我有一个更复杂的指针,但即使在这个简单的示例中,我也始终如一地遇到这个问题。我认为它与 String(cString:typedPointer( 有关,但我没有看到我如何分配错误的内存大小,从而导致任何堆头或数据被踩踏。

更新 - 请参阅下面的答案

看起来我需要一个空终止符作为指针中的最后一个字节,否则字符串将不知道指针的结束位置。

其他选项...

您可以从UnsafeMutableRawPointer创建Data

let pointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
pointer.storeBytes(of: 77, as: UInt8.self)
pointer.advanced(by: 1).storeBytes(of: 105, as: UInt8.self)
(pointer+2).storeBytes(of: 107, as: UInt8.self)
(pointer+3).storeBytes(of: 101, as: UInt8.self)
let data = Data(bytes: pointer, count: 4)
let readableData = String(data: data, encoding: .utf8)

否则,String.init(bytes:encoding:)是另一个不声明以 null 结尾的序列的初始值设定项:

let pointer = UnsafeMutableRawPointer.allocate(byteCount: 4, alignment: 1)
pointer.storeBytes(of: 77, as: UInt8.self)
pointer.advanced(by: 1).storeBytes(of: 105, as: UInt8.self)
(pointer+2).storeBytes(of: 107, as: UInt8.self)
(pointer+3).storeBytes(of: 101, as: UInt8.self)
let urbp = UnsafeRawBufferPointer(start: pointer, count: 4)
let readableData = String(bytes: urbp, encoding: .utf8)

请尝试。

通了。

根据String(cString: fooParam)的文件

  • 参数 cString:指向以 null 结尾的 UTF-8 代码序列的指针。

如果要发送的数据不是以 null 结尾的,则此初始值设定项将不知道指针数据的结束位置,并且会出现"意外行为",有时失败,有时成功。

解决方案是,如果您尝试传入的数据不是以 null 结尾的,则添加 null 终止符。

例如:

let pointer = UnsafeMutableRawPointer.allocate(byteCount: 5, alignment: 1)
pointer.storeBytes(of: 77, as: UInt8.self)
pointer.advanced(by: 1).storeBytes(of: 105, as: UInt8.self)
(pointer+2).storeBytes(of: 107, as: UInt8.self)
(pointer+3).storeBytes(of: 101, as: UInt8.self)
(pointer+4).storeBytes(of: 0, as: UInt8.self)
let typedPointer = pointer.bindMemory(to: UInt8.self, capacity: 5)

let readableData = String(cString: typedPointer)

在我实际做的事情中,我没有原始引用,而是键入的引用。同样的事情是通过做来实现的

somePointer.advanced(by: 4).pointee = 0