Aviso: A inicialização de 'UnsafeBufferPointer <T>' resulta em um ponteiro de buffer pendente

10

Após a atualização para o Swift 5.2 / Xcode 11.4, recebi um aviso para o seguinte código:

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 deixe ponteiro = UnsafeBufferPointer (start: & valor, a contagem: 1) Eu tenho

A inicialização de 'UnsafeBufferPointer' resulta em um ponteiro de buffer pendente

Posso usar @silenceWarning, mas é uma solução suja. Talvez eu precise armazenar o ponteiro em algum lugar e limpá-lo no futuro?

Exey Panteleev
fonte
É estranho como todo mundo corre para atualizar sem se preocupar em ler as notas de lançamento, que são bastante explícitas sobre isso.
matt
developer.apple.com/documentation/xcode_release_notes/… e procure por danling. O bugs.swift.org/browse/SR-2790 parece ter uma discussão mais completa sobre isso.
Roy Falk

Respostas:

3

Isso nunca foi seguro, tão feliz que a equipe Swift o limpou:

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

No final desta linha de código, pointeré imediatamente inválido. Não há promessa de que valueexista na próxima linha de código. Não tenho certeza do que você estava tentando alcançar aqui, mas nunca foi uma maneira segura de fazer isso. O que você provavelmente está procurando é um dos .withUnsafeBytesmétodos, que depende do que você estava trabalhando.

Rob Napier
fonte
3
Embora sua resposta esteja provavelmente correta, seria muito melhor se você mostrasse um exemplo de como isso pode falhar. Existem alguns exemplos ( stackoverflow.com/a/27456220/5276890 ) de peças fundidas e conversões usando Unsafe * Pointer flutuando ao redor que agora geram esse aviso.
Roy Falk
3

Eu tinha um código que parecia quase exatamente o que você estava fazendo e estava recebendo o mesmo aviso. Os meus diferiram ligeiramente de uma maneira que é relevante para a discussão

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

Isso ainda gera o aviso de que o UnsafeBufferPointer está produzindo um ponteiro pendente, mas as dicas dizem "produz um ponteiro válido apenas pela duração da chamada para 'init (start: count :)'"

Mas o retorno de UnsafeBufferPointer não está atribuído a nada, então eu não poderia usá-lo fora do escopo do init se tentasse. Portanto, o compilador aqui está me alertando contra fazer algo que não posso fazer de qualquer maneira.

Eu acho que Data.init (buffer :) poderia estar armazenando o ptr, mas eu assumiria que, se ele aceita um UnsafeBufferPointer, está aceitando a responsabilidade de usá-lo corretamente

Enfim, isso ainda não resolve o seu problema. Eu contornei o aviso com isso

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

E isso não gera o aviso e parece funcionar (no meu aplicativo de qualquer maneira). A questão de saber se é aprovada pelos especialistas aqui é outra questão.

Meio que me deixa nostálgico pelos dias de HLock e HUnlock

greg
fonte
3

Eu também recebi esses avisos irritantes.

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

Considerando @ resposta de Greg, eu coloquei o Data.appendno withUnsafePointerfechamento 's, e ele não mostra advertências mais.

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

Aqui está a extensão

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