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

Модуль 3.2 — Тестирование и фаззинг

Слайды

Упражнение 3.2.1: Декодирование DNS

В этом упражнении вы потренируетесь в модульном тестировании, измерении покрытия кода и написании небольшого фаззера с помощью cargo-fuzz.

Вы будете работать с функцией dns_decode, которая реализует часть декодирования доменных имён из RFC 1035. В этом формате каждая часть доменного имени кодируется префиксом из одного байта с её длиной, за которым следуют байты самой части. Само доменное имя завершается нулевым байтом: «пустая часть» означает конец имени. Точки между частями не кодируются.

Например, mailcrab.tweedegolf.nl можно закодировать как b"\x08mailcrab\x0Atweedegolf\x02nl\0". При этом действуют два ограничения:

  • Максимальный размер одной части — 63 байта.
  • Максимальный размер полного доменного имени (включая точки) — 255 байт.

Мы подготовили «первую попытку» в exercises/3-crate-engineering/2-testing/1-dns-decode. Определение функции находится в src/lib.rs, а рядом есть src/main.rs, чтобы можно было запускать функцию интерактивно. В src/lib.rs даже есть несколько модульных тестов, так что старт хороший! Однако функция далеко не полностью протестирована и содержит ошибки. Возможно, вы их найдёте?

Упражнение 3.2.1.A: Улучшаем покрытие кода

Если вы ещё этого не делали, установите cargo-llvm-cov:

cargo install cargo-llvm-cov

После этого посмотреть покрытие можно, запустив cargo llvm-cov из каталога крейта. Также можно выполнить cargo llvm-cov --open, чтобы открыть отчёт о покрытии в браузере.

Хотя покрытие строк высокое, как видно, оно не равно 100%. Напишите модульный тест, чтобы покрытие строк для src/lib.rs действительно достигло 100% (на практике этого редко удаётся добиться).

Упражнение 3.2.1.B: Фаззинг

Даже при 100% покрытии в коде могут скрываться ошибки. Найдём их с помощью cargo-fuzz. Чтобы его установить, нужно не только установить cargo-fuzz, но и использовать тулчейн «nightly», который содержит все экспериментальные возможности. Установить оба инструмента можно так:

rustup toolchain install nightly
cargo install cargo-fuzz

Затем из каталога exercises/3-crate-engineering/2-testing/1-dns-decode выполните cargo fuzz init. Эта команда создаст подкаталог fuzz/ с шаблоном цели для фаззинга. (Обратите внимание: подкаталог fuzz/ — это небольшой проект на Rust со своим Cargo.toml! Поэтому в него тоже можно добавлять зависимости, как в любой другой проект на Rust.)

Список доступных целей можно посмотреть командой:

cargo +nightly fuzz list

Цель fuzz_target_1 уже можно запустить командой

cargo +nightly fuzz run fuzz_target_1

Но она не найдёт ошибок. Отредактируйте fuzz/fuzz_targets/fuzz_target_1.rs, чтобы она делала что-то интересное! Также подумайте о добавлении других целей командой cargo +nightly fuzz add <TARGETNAME>.

Подсказки:

  • Чтобы обратиться к функции dns_decode, импортируйте её в цели фаззинга:
    #![allow(unused)]
    fn main() {
    use dns_parse::decode_dns_name;
    }
  • Начните с простого: напишите фаззер, который просто вызывает dns_decode для входных данных &[u8], и проверьте, находит ли он падения.
  • Попробуйте проверить два других свойства, которые должны выполняться для dns_decode:
    • максимальная длина части — 63 байта;
    • максимальная длина доменного имени — 255 байт.
  • Как и в модульных тестах, assert! — ваш лучший друг.