Попередження: Ініціалізація 'UnsafeBufferPointer <T>' призводить до висячого вказівника буфера


10

Після оновлення до Swift 5.2 / Xcode 11.4 отримано попередження про наступний код:

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

У рядку нехай покажчик = UnsafeBufferPointer (start: & value, count: 1) Я отримав

Ініціалізація 'UnsafeBufferPointer' призводить до висячого вказівника буфера

Я можу використовувати @silenceWarning, але це брудне рішення. Можливо, мені потрібно десь зберігати вказівник і чистити його в майбутньому?


Як не дивно, як усі кидаються оновлюватись, не турбуючись читати нотатки до випуску, які про це доволі явні.
мат

developer.apple.com/documentation/xcode_release_notes/… та шукайте танцюючих. bugs.swift.org/browse/SR-2790, здається, має більш повне обговорення цього питання.
Рой Фолк

Відповіді:


3

Це ніколи не було безпечно, тому радий, що команда Свіфт прибрала це:

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

В кінці цього рядка код pointerнедійсний. Немає обіцянки, що вона valueіснує навіть у наступному рядку коду. Я не впевнений, чого ви намагалися досягти тут, але це ніколи не було безпечним способом зробити це. Те, що ви, ймовірно, шукаєте - це один із .withUnsafeBytesметодів, який залежить від того, над чим працювали.


3
Хоча ваша відповідь, ймовірно, правильна, було б набагато краще, якби ви показали приклад того, як це може провалитися. Є кілька прикладів ( stackoverflow.com/a/27456220/5276890 ) кастингів та конверсій за допомогою небезпечних * Покажчик, що плаває навколо, тепер генерує це попередження.
Рой Фолк

3

У мене був код, який виглядав майже точно, що ви робите, і отримував таке ж попередження. Моя незначно відрізнялася тим, що стосується дискусії

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

Це все ще створює попередження про те, що UnsafeBufferPointer створює звисаючий покажчик, але підказки говорять, що "створює покажчик, дійсний лише протягом тривалості виклику" init (start: count :) ""

Але повернення з UnsafeBufferPointer не призначено ні для чого, тому я не зміг би використати його поза межами програми init, якщо б спробував. Тож компілятор тут застерігає мене від того, щоб робити щось, чого я не можу зробити.

Я думаю, що Data.init (буфер:) може зберігати ptr, але я вважаю, що якщо він приймає UnsafeBufferPointer, він бере на себе відповідальність за правильне його використання.

У всякому разі, це все ще не дуже вирішує вашу проблему. З цим я обійшов попередження

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

І це не генерує попередження і, здається, працює (у моєму додатку все одно). Чи проходить це питання з експертами тут - інша справа.

Вигляд мене ностальгує за днями HLock та HUnlock


3

Я також зустрівся з цими прикрими попередженнями.

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

Враховуючи відповідь @ greg, я ставлю його Data.appendдо withUnsafePointerзакриття, і він більше не показує попередження.

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

Ось розширення

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

DRYappend(.init(value: value))
Лев Дабус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.