将UnsafeMutablePointer <uint8>转换为String时,堆缓冲区溢出

时间:2019-03-25 16:46:33

标签: ios swift overflow heap-memory

执行以下操作时,我从Address Sanitizer收到错误消息:

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)有关,但是我没有看到如何分配错误的内存大小,这会导致堆头文件或数据受到严重破坏。

更新-请参见下面的答案

好像我需要一个空终止符,因为指针中的最后一个字节或字符串将不知道指针的结尾。

2 个答案:

答案 0 :(得分:1)

其他选项...

您可以从Data创建UnsafeMutableRawPointer

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)

请尝试。

答案 1 :(得分:0)

弄清楚了。

根据String(cString: fooParam)

的文档
  
      
  • 参数cString:指向以空值终止的UTF-8代码序列的指针。
  •   

如果您要发送的数据不是以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