Ostrzeżenie: Inicjalizacja „UnsafeBufferPointer <T>” powoduje zwisający wskaźnik bufora

10

Po aktualizacji do Swift 5.2 / Xcode 11.4 pojawiło się ostrzeżenie do następującego kodu:

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) }
    }
}

On line niech wskaźnik = UnsafeBufferPointer (start: i wartość, liczba: 1) Mam

Inicjalizacja „UnsafeBufferPointer” powoduje zwisający wskaźnik bufora

Mogę użyć @silenceWarning, ale to brudne rozwiązanie. Może muszę gdzieś przechowywać wskaźnik i czyścić go w przyszłości?

Exey Panteleev
źródło
Dziwne, że wszyscy spieszą się z aktualizacją, nie zawracając sobie głowy czytaniem informacji o wydaniu, które są dość jednoznaczne na ten temat.
mat
developer.apple.com/documentation/xcode_release_notes/… i wyszukaj danling. bugs.swift.org/browse/SR-2790 wydaje się mieć pełniejszą dyskusję na ten temat.
Roy Falk

Odpowiedzi:

3

To nigdy nie było bezpieczne, więc cieszę się, że zespół Swift go wyczyścił:

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

Na końcu tego wiersza kodu pointerjest natychmiast nieważny. Nie ma obietnicy, która valueistnieje nawet w następnym wierszu kodu. Nie jestem pewien, co próbowaliście tutaj osiągnąć, ale nigdy nie był to bezpieczny sposób. Prawdopodobnie szukasz jednej z .withUnsafeBytesmetod, która zależy od tego, nad czym pracowałeś.

Rob Napier
źródło
3
Chociaż twoja odpowiedź jest prawdopodobnie prawidłowa, byłoby znacznie lepiej, gdybyś pokazał przykład, jak to może się nie powieść. Istnieje kilka przykładów ( stackoverflow.com/a/27456220/5276890 ) rzutowań i konwersji przy użyciu Niebezpiecznego * wskaźnika pływającego wokół, który teraz generuje to ostrzeżenie.
Roy Falk
3

Miałem kod, który wyglądał prawie dokładnie to, co robisz, i otrzymywałem to samo ostrzeżenie. Mój różni się nieznacznie w sposób istotny dla dyskusji

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

Nadal generuje to ostrzeżenie, że UnsafeBufferPointer produkuje zwisający wskaźnik, ale podpowiedzi mówią „produkuje wskaźnik ważny tylko przez czas trwania wywołania„ init (start: count :) ””

Ale powrót z UnsafeBufferPointer nie jest przypisany do niczego, więc nie mogłem użyć go poza zakresem init, gdybym spróbował. Kompilator tutaj ostrzega mnie przed zrobieniem czegoś, czego i tak nie mogę zrobić.

Wydaje mi się, że Data.init (bufor:) może przechowywać ptr, ale zakładam, że jeśli zaakceptuje wskaźnik UnsafeBufferPointer, przyjmuje odpowiedzialność za prawidłowe użycie go

W każdym razie nadal nie rozwiązuje to problemu. Dzięki temu udało mi się obejść ostrzeżenie

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)
}

I to nie generuje ostrzeżenia i wydaje się działać (i tak w mojej aplikacji). To, czy przejdzie to w sporze z ekspertami, to inna sprawa.

Niby nostalgicznie za dniami HLock i HUnlock

greg
źródło
3

Spotkałem także te irytujące ostrzeżenia.

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)) 

Biorąc pod uwagę odpowiedź @ Greg, wkładam Data.appendw withUnsafePointer„s zamknięcia, i nie wykazuje już ostrzeżenia.

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

Oto rozszerzenie

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))
        }
    }
}
Chen OT
źródło
DRYappend(.init(value: value))
Leo Dabus