【问题标题】:Heap Buffer Overflow when converting UnsafeMutablePointer<UInt8> to String将 UnsafeMutablePointer<UInt8> 转换为 String 时堆缓冲区溢出
【发布时间】:2019-03-25 16:46:33
【问题描述】:

在执行以下操作时,我从 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) 有关,但我没有看到我如何分配错误的内存大小,这会导致任何堆头或数据被踩踏。

更新 - 请参阅下面的答案

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

【问题讨论】:

    标签: ios swift overflow heap-memory


    【解决方案1】:

    其他选项...

    您可以从您的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)
    

    请尝试。

    【讨论】:

    • 这两种方法都有效,但确实依赖于 .utf8 格式,这可以满足大多数需求。很好的答案! + 1
    【解决方案2】:

    想通了。

    根据String(cString: fooParam)的文档

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

    如果您发送的数据不是以空值结尾的,则此初始化程序将不知道指针数据的结束位置,并且会出现“意外行为”,有时会失败,有时会成功。

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

    例如:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-11
      • 1970-01-01
      • 2010-11-11
      • 2021-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多