Peringatan: Inisialisasi 'UnsafeBufferPointer <T>' menghasilkan penunjuk buffer yang menggantung

10

Setelah pembaruan ke Swift 5.2 / Xcode 11.4 mendapat peringatan untuk kode berikut:

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

Point let let on line = UnsafeBufferPointer (mulai: & nilai, hitung: 1) saya dapatkan

Inisialisasi hasil 'UnsafeBufferPointer' di pointer buffer menggantung

Saya bisa menggunakan @silenceWarning tapi ini solusi kotor. Mungkin saya perlu menyimpan pointer di suatu tempat dan membersihkannya di masa depan?

Exey Panteleev
sumber
Sungguh aneh bagaimana semua orang bergegas untuk memperbarui tanpa repot-repot membaca catatan rilis, yang cukup eksplisit tentang ini.
matt
developer.apple.com/documentation/xcode_release_notes/… dan cari danling. bugs.swift.org/browse/SR-2790 tampaknya memiliki diskusi yang lebih lengkap tentang ini.
Roy Falk

Jawaban:

3

Ini tidak pernah aman, sangat senang bahwa tim Swift telah membersihkannya:

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

Pada akhir baris kode ini, pointerlangsung tidak valid. Tidak ada janji yang valuebahkan ada di baris kode berikutnya. Saya tidak yakin apa yang ingin Anda capai di sini, tetapi ini tidak pernah cara yang aman untuk melakukannya. Apa yang mungkin Anda cari adalah salah satu .withUnsafeBytesmetode, yang tergantung pada apa yang sedang Anda kerjakan.

Rob Napier
sumber
3
Meskipun jawaban Anda mungkin benar, akan jauh lebih baik jika Anda menunjukkan contoh bagaimana ini bisa gagal. Ada beberapa contoh ( stackoverflow.com/a/27456220/5276890 ) dari casting dan konversi menggunakan Unsafe * Pointer yang beredar yang sekarang menghasilkan peringatan ini.
Roy Falk
3

Saya memiliki kode yang terlihat hampir persis seperti apa yang Anda lakukan dan mendapatkan peringatan yang sama. Milik saya sedikit berbeda dengan cara yang relevan dengan diskusi

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

Ini masih menghasilkan peringatan bahwa UnsafeBufferPointer menghasilkan Pointer menggantung tetapi petunjuk mengatakan "menghasilkan pointer yang hanya valid selama durasi panggilan untuk 'init (start: count :)'"

Tetapi pengembalian dari UnsafeBufferPointer tidak ditugaskan untuk apa pun, jadi saya tidak bisa menggunakannya di luar ruang lingkup init jika saya mencoba. Jadi kompiler di sini memperingatkan saya untuk tidak melakukan sesuatu yang tidak bisa saya lakukan.

Saya kira Data.init (buffer:) dapat menyimpan ptr, tetapi saya akan menganggap bahwa jika ia menerima UnsafeBufferPointer, ia menerima tanggung jawab untuk menggunakannya dengan benar

Bagaimanapun, itu masih tidak benar-benar memperbaiki masalah Anda. Saya mendapat peringatan dengan ini

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

Dan ini tidak menghasilkan peringatan dan tampaknya berfungsi (dalam aplikasi saya sih). Apakah hal itu sesuai dengan para ahli di sini adalah masalah lain.

Agak membuat saya nostalgia untuk hari-hari HLock dan HUnlock

greg
sumber
3

Saya juga bertemu peringatan yang menjengkelkan ini.

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

Mengingat jawaban @ greg, saya menempatkan Data.appendke dalam withUnsafePointer's penutupan, dan tidak menunjukkan peringatan lagi.

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

Ini ekstensi

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