Warnung: Die Initialisierung von 'UnsafeBufferPointer <T>' führt zu einem baumelnden Pufferzeiger

10

Nach dem Update auf Swift 5.2 / Xcode 11.4 wurde eine Warnung zu folgendem Code angezeigt:

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

In der Zeile let pointer = UnsafeBufferPointer (Start: & Wert, Anzahl: 1) habe ich

Die Initialisierung von 'UnsafeBufferPointer' führt zu einem baumelnden Pufferzeiger

Ich kann @silenceWarning verwenden, aber es ist eine schmutzige Lösung. Vielleicht muss ich den Zeiger irgendwo aufbewahren und in Zukunft bereinigen?

Exey Panteleev
quelle
Es ist seltsam, wie jeder schnell ein Update durchführt, ohne sich die Mühe zu machen, die Versionshinweise zu lesen, die diesbezüglich ziemlich explizit sind.
Matt
developer.apple.com/documentation/xcode_release_notes/… und suche nach danling. bugs.swift.org/browse/SR-2790 scheint eine ausführlichere Diskussion darüber zu haben.
Roy Falk

Antworten:

3

Das war nie sicher, so froh, dass das Swift-Team es aufgeräumt hat:

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

Am Ende dieser Codezeile pointerist sofort ungültig. Es gibt kein Versprechen, das valueüberhaupt in der nächsten Codezeile existiert. Ich bin mir nicht sicher, was Sie hier erreichen wollten, aber dies war nie ein sicherer Weg, dies zu tun. Was Sie wahrscheinlich suchen, ist eine der .withUnsafeBytesMethoden, die davon abhängt, woran Sie gearbeitet haben.

Rob Napier
quelle
3
Während Ihre Antwort wahrscheinlich richtig ist, wäre es viel besser, wenn Sie ein Beispiel dafür zeigen würden, wie dies fehlschlagen könnte. Es gibt einige Beispiele ( stackoverflow.com/a/27456220/5276890 ) für Castings und Konvertierungen mit Unsafe * Pointer, die jetzt diese Warnung generieren.
Roy Falk
3

Ich hatte Code, der fast genau so aussah, wie Sie es taten, und der die gleiche Warnung erhielt. Meins unterschied sich geringfügig in einer Weise, die für die Diskussion relevant ist

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

Dies erzeugt immer noch die Warnung, dass UnsafeBufferPointer einen baumelnden Zeiger erzeugt, aber die Hinweise besagen "erzeugt einen Zeiger, der nur für die Dauer des Aufrufs von 'init (start: count :)' gültig ist".

Die Rückgabe von UnsafeBufferPointer ist jedoch nichts zugewiesen, sodass ich sie nicht außerhalb des Bereichs des Init verwenden könnte, wenn ich es versuchen würde. Der Compiler hier warnt mich also davor, etwas zu tun, was ich sowieso nicht tun kann.

Ich denke, Data.init (buffer :) könnte den ptr speichern, aber ich würde annehmen, dass wenn es einen UnsafeBufferPointer akzeptiert, es die Verantwortung für die ordnungsgemäße Verwendung übernimmt

Wie auch immer, das behebt Ihr Problem immer noch nicht wirklich. Damit habe ich die Warnung umgangen

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

Und dies erzeugt keine Warnung und scheint zu funktionieren (in meiner Anwendung sowieso). Ob es hier mit den Experten zusammenkommt, ist eine andere Frage.

Das macht mich irgendwie nostalgisch für die Tage von HLock und HUnlock

greg
quelle
3

Ich habe auch diese nervigen Warnungen getroffen.

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

In Anbetracht der Antwort von @ greg habe ich das Data.appendin geschlossen withUnsafePointer, und es werden keine Warnungen mehr angezeigt.

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

Hier ist die Erweiterung

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
quelle
DRYappend(.init(value: value))
Leo Dabus