Комментарии 3
То есть получается всё, как всегда. Средства языка и компилятора не лечат проблемы алгоритмов.
По работе с памятью приколов не навертели и хорошо. А алгоритмы поправят. 😁
Реалистичный паттерн: каждый шрам = новый newtype или smart constructor с приватным полем. Тогда чтобы получить значение, ты обязан пройти через проверку. Это и есть “шрам в сигнатуре”.
Но причём тут Rust? Это как раз проблема Си что он стёр намерения. Rust же даёт возможность фиксировать шрамы в сигнатурах, значит не превратится в легаси.
Советы от LLM, но стоит прислушаться
Самые дешёвые:
1… Правильные базовые типы
имена файлов: &Path / &OsStr, не String
данные файла: &[u8], не &str, пока UTF-8 не доказан
размеры: u64/u128 + checked_* + try_from Это уже сохраняет кучу шрамов.
2… Именованные guard-функции
checked_alloc_len(count, elem_size)
read_retry_eintr
write_all_or_broken_pipe
parse_block_size Шрам должен жить не в комментарии, а в одной функции, которую все зовут.
3… enum вместо bool
FollowSymlinks::{Never, Cmdline, Always}
OverwriteMode::{NoClobber, Force, Interactive} Это дешёвый способ зафиксировать намерение.
4… Newtype с приватным полем
BlockSize, MaxDepth, Suffix, LineCount
получение только через TryFrom/constructor Шрам переезжает в constructor.
Средние:
5… Разделять сырое и проверенное
CliPath
ResolvedPath
UserPattern
ValidatedPattern Не смешивать “пришло снаружи” и “уже проверено”.
6… Модульные границы для опасных тем
fs
pathbytes
locale
parse_size
tempfile Снаружи не дают делать syscall “как попало”.
7… FD-oriented API
openat, fstatat, работа от DirFd
меньше TOCTOU и symlink-race Для coreutils это один из самых ценных шрамов.
8… Явные ошибки
enum Error { Overflow, InvalidSuffix, InvalidEncoding, … } Тогда знание видно в сигнатуре, а не только в тексте.
Дорогие:
9… Typestate
ParsedArgs -> ValidatedArgs
Walker<Physical> / Walker<Logical>
TempFile<Open> / TempFile<Persisted> Нужно только там, где реально есть фазы.
10… Pure core + thin shell
алгоритм отдельно
syscalls/CLI/locale отдельно Так шрамы легче закреплять и тесты живут дольше.
11… Изолировать unsafe
маленький модуль
у каждого unsafe блока // Safety: … Это тоже шрам, но уже текстовый и локальный.
12… Fuzz/property/corpus Не типы, но для coreutils часть шрамов только так и держится.
Если совсем кратко, патч после бага должен оставлять один из трёх следов:
новый тип
новый constructor/guard
новый API-барьер
Топ-3 по ROI для coreutils:
не использовать String для путей
вся арифметика размеров только через checked wrappers
fd/openat стиль вместо “всё через path string”
И да, плохая стратегия - делать новый тип под каждый исторический баг. Нужны типы под класс ошибок, не под музей патчей.
🧮 Модель: #GPT 5.4 Pro

44 CVE в uutils: что Rust ловит, а что нет на границе с системой