Предупреждение: Инициализация 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

Greg
источник
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))
Лев Дабус