Предупреждение: Инициализация UnsafeBufferPointer <T> приводит к зависанию указателя буфера


10

После обновления до Swift 5.2 / Xcode 11.4 появилось предупреждение о следующем коде:

extension Data {

    init<T>(from value: T) {
        var value = value
        let pointer = UnsafeBufferPointer(start: &value, count: 1)
        self.init(buffer: pointer)
    }

    func to<T>(type: T.Type) -> T {
        return self.withUnsafeBytes { $0.load(as: T.self) }
    }
}

В строке пусть указатель = UnsafeBufferPointer (начало: & значение, количество: 1) я получил

Инициализация «UnsafeBufferPointer» приводит к зависанию указателя буфера

Я могу использовать @silenceWarning, но это грязное решение. Может быть, мне нужно где-то хранить указатель и очистить его в будущем?


Странно, что все спешат обновиться, не удосужившись прочитать примечания к выпуску, в которых об этом явно сказано.
матовый

developer.apple.com/documentation/xcode_release_notes/… и ищите danling. bugs.swift.org/browse/SR-2790, по- видимому, более полно обсуждает это.
Рой Фальк

Ответы:


3

Это никогда не было безопасно, так рад, что команда Swift исправила это:

let pointer = UnsafeBufferPointer(start: &value, count: 1)

В конце этой строки кода, pointerсразу же становится недействительным. Там нет обещания, что valueдаже существует в следующей строке кода. Я не уверен, чего вы пытались достичь здесь, но это никогда не было безопасным способом сделать это. Вероятно, вы ищете один из .withUnsafeBytesметодов, который зависит от того, над чем вы работали.


3
Хотя ваш ответ, вероятно, правильный, было бы гораздо лучше, если бы вы показали пример того, как это может не сработать. Есть несколько примеров ( stackoverflow.com/a/27456220/5276890 ) кастингов и конверсий с использованием Unsafe * Pointer, плавающих вокруг, которые теперь генерируют это предупреждение.
Рой Фальк

3

У меня был код, который выглядел почти точно, что вы делали, и получал то же предупреждение. Мой немного отличался таким образом, который имеет отношение к обсуждению

init<T>(from value: T) {
    var value = value
    self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}

Это по-прежнему генерирует предупреждение о том, что UnsafeBufferPointer создает висячий указатель, но подсказки говорят: «создает указатель, действительный только на время вызова init (start: count :) '»

Но возврат из UnsafeBufferPointer ни к чему не привязан, поэтому я не смог использовать его вне области init, если попытался. Так что компилятор здесь предупреждает меня о том, чтобы я не делал то, что я не могу сделать.

Я думаю, Data.init (buffer:) может хранить ptr, но я предполагаю, что если он принимает UnsafeBufferPointer, он принимает на себя ответственность за его правильное использование

В любом случае, это все еще не решит твою проблему. Я обошел предупреждение с этим

init<T>(from value: T) {
    var value = value
    var myData = Data()
    withUnsafePointer(to:&value, { (ptr: UnsafePointer<T>) -> Void in
        myData = Data( buffer: UnsafeBufferPointer(start: ptr, count: 1))
    })
    self.init(myData)
}

И это не генерирует предупреждение и, кажется, работает (в любом случае, в моем приложении). Вопрос о том, пройдет ли это экспертами, - это другой вопрос.

В некотором роде я испытываю ностальгию по временам HLock и HUnlock


3

Я также встретил эти досадные предупреждения.

var str = "aaaaabbbbbccccc"
var num1 = 1
var num2 = 22

var data = Data()
// Initialization of 'UnsafeBufferPointer<String>' results in a dangling buffer pointer
data.append(UnsafeBufferPointer(start: &str, count: 1)) 
// Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointer
data.append(UnsafeBufferPointer(start: &num1, count: 1))
// Initialization of 'UnsafeBufferPointer<Int>' results in a dangling buffer pointer 
data.append(UnsafeBufferPointer(start: &num2, count: 1)) 

Принимая во внимание ответ @ greg, я помещаю его Data.appendв withUnsafePointerзакрытие, и оно больше не показывает предупреждений.

withUnsafePointer(to: &str) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok
withUnsafePointer(to: &num1) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok
withUnsafePointer(to: &num2) { data.append(UnsafeBufferPointer(start: $0, count: 1)) } // ok

Вот расширение

extension Data {
    init<T>(value: T) {
        self = withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) -> Data in
            return Data(buffer: UnsafeBufferPointer(start: ptr, count: 1))
        }
    }

    mutating func append<T>(value: T) {
        withUnsafePointer(to: value) { (ptr: UnsafePointer<T>) in
            append(UnsafeBufferPointer(start: ptr, count: 1))
        }
    }
}

СУХОЙappend(.init(value: value))
Лев Дабус
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.