Переполнение буфера кучи при преобразовании UnsafeMutablePointerнанизывать - PullRequest
0 голосов
/ 25 марта 2019

Я получаю сообщение об ошибке от 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 ]

1 голос
/ 25 марта 2019

Другие параметры ...

Вы можете создать 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:) - это другой инициализатор, который не требует нулевойзавершенная последовательность:

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)

Пожалуйста, попробуйте.

0 голосов
/ 25 марта 2019

Разобрался.

Согласно документации String(cString: fooParam)

  • Параметр cString: указатель на кодовую последовательность 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...