Avertissement: l'initialisation de 'UnsafeBufferPointer <T>' entraîne un pointeur de tampon pendant

10

Après la mise à jour vers Swift 5.2 / Xcode 11.4, un avertissement a été envoyé au code suivant:

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 let pointer = UnsafeBufferPointer (start: & value, count: 1) I got

L'initialisation de «UnsafeBufferPointer» entraîne un pointeur de tampon pendant

Je peux utiliser @silenceWarning mais c'est une sale solution. Peut-être que je dois stocker le pointeur quelque part et le nettoyer à l'avenir?

Exey Panteleev
la source
Il est étrange que tout le monde se précipite pour mettre à jour sans prendre la peine de lire les notes de version, qui sont assez explicites à ce sujet.
mat
developer.apple.com/documentation/xcode_release_notes/… et recherchez danling. bugs.swift.org/browse/SR-2790 semble avoir une discussion plus complète à ce sujet.
Roy Falk

Réponses:

3

Cela n'a jamais été sûr, si heureux que l'équipe Swift l'ait nettoyé:

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

À la fin de cette ligne de code, pointerest immédiatement invalide. Il n'y a aucune promesse qui valueexiste même à la prochaine ligne de code. Je ne sais pas ce que vous tentiez de réaliser ici, mais ce n'était jamais un moyen sûr de le faire. Ce que vous recherchez probablement est l'une des .withUnsafeBytesméthodes, qui dépend de ce sur quoi vous travailliez.

Rob Napier
la source
3
Bien que votre réponse soit probablement correcte, il serait préférable que vous montriez un exemple de la façon dont cela pourrait échouer. Il existe quelques exemples ( stackoverflow.com/a/27456220/5276890 ) de transtypages et de conversions utilisant un pointeur non sécurisé * flottant autour qui génèrent désormais cet avertissement.
Roy Falk
3

J'avais un code qui ressemblait presque exactement à ce que vous faisiez et recevait le même avertissement. Le mien différait légèrement d'une manière pertinente pour la discussion

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

Cela génère toujours l'avertissement que UnsafeBufferPointer produit un pointeur suspendu, mais les conseils indiquent "produit un pointeur valide uniquement pour la durée de l'appel à" init (start: count :) ""

Mais le retour de UnsafeBufferPointer n'est affecté à rien, donc je ne pourrais pas l'utiliser en dehors de la portée de l'initialisation si j'essayais. Donc, le compilateur ici m'avertit de ne pas faire quelque chose que je ne peux pas faire de toute façon.

Je suppose que Data.init (buffer:) pourrait stocker le ptr, mais je suppose que s'il accepte un UnsafeBufferPointer, il accepte la responsabilité de l'utiliser correctement

Quoi qu'il en soit, cela ne résout toujours pas vraiment votre problème. J'ai contourné l'avertissement avec ça

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

Et cela ne génère pas l'avertissement et semble fonctionner (dans mon application de toute façon). Que cela passe avec les experts ici est une autre question.

Cela me rend nostalgique des jours de HLock et HUnlock

Greg
la source
3

J'ai également rencontré ces avertissements ennuyeux.

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

Considérant @ la réponse de greg, je mets le Data.appenddans withUnsafePointerla fermeture « , et il ne montre pas les avertissements plus.

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

Voici l'extension

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