Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Открытый небезопасный Rust

// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0

pub fn copy(dest: &mut [u8], source: *const u8) {
    let source = {
        let mut len = 0;

        let mut end = source;
        while unsafe { *end != 0 } {
            len += 1;
            end = unsafe { end.add(1) };
        }

        unsafe { std::slice::from_raw_parts(source, len + 1) }
    };

    for (dest, src) in dest.iter_mut().zip(source) {
        *dest = *src;
    }
}

fn main() {
    let a = [114, 117, 115, 116].as_ptr();
    let b = &mut [82, 85, 83, 84, 0];

    println!("{}", String::from_utf8_lossy(b));
    copy(b, a);
    println!("{}", String::from_utf8_lossy(b));
}

Функциональность копирования байтов из одного места в другое остаётся прежней.

«Однако теперь нужно вручную создать срез. Для этого сначала надо найти конец данных».

«Поскольку мы работаем с текстом, используем соглашение C о строках с завершающим нулём».

Скомпилируйте код. Убедитесь, что вывод остался прежним.

«Некорректная функция может всё равно правильно работать на каких-то входных данных. То, что ваши тесты проходят, ещё не значит, что функция корректна».

«Кто-нибудь видит проблемы?»

  • Читаемость: код трудно быстро просмотреть
  • Указатель source может быть нулевым
  • Указатель source может быть висящим, то есть указывать на освобождённую или неинициализированную память
  • source может не заканчиваться нулевым байтом

«Допустим, мы не можем менять сигнатуру функции. Какие улучшения кода можно сделать, чтобы устранить эти проблемы?»

  • Нулевой указатель: добавьте проверку на null с ранним возвратом (if source.is_null() { return; })
  • Читаемость: используйте проверенную библиотеку, а не реализуйте поиск первого нулевого байта сами

«Однако некоторые требования безопасности невозможно проверить защитным кодом, а именно:»

  • висящий указатель
  • отсутствие завершающего нулевого байта

«Как сделать эту функцию корректной?»

  • Либо
    • Измените тип входного аргумента source на что-то с известной длиной, то есть используйте срез, как в предыдущем примере.
  • Или
    • Пометьте функцию как unsafe
    • Задокументируйте предусловия безопасности