Из ядра Linux выпилили strncpy
19 июня Линус Торвальдс принял merge, окончательно удаливший из ядра функцию strncpy. На это ушло шесть лет работы, 362 коммита и 70 разработчиков. Пример того, почему просто заменить небезопасную функцию в C вовсе не просто.
Буква «n» в названии создаёт иллюзию контроля: strncpy(dst, src, n) копирует максимум n байт. Однако документация предупреждает, что это не строковая функция, она создаёт null-padded character sequence. Появившись в AT&T Unix около 1979 года для работы с именами файлов в директориях (поля фиксированной ширины), strncpy десятилетиями использовалась в обычном коде как безопасная замена strcpy. Но если длина источника >= n, терминальный \0 не ставится, и любой strlen или printk улетит за буфер. Если источник короче n, то весь остаток до n забивается нулями, что порождает ненужную нагрузку.
Заменить strncpy одной функцией невозможно: под разные намерения нужен разный инструмент:
strscpy() — для нормальной строки с терминатором.
strscpy_pad() — то же с обнулением хвоста.
strtomem() / strtomem_pad() — для полей фиксированной ширины без терминатора.
memcpy_and_pad() — для bounded-копии из источника, который может не иметь завершающего нуля.
memtostr() / memtostr_pad() — обратный случай.
memcpy() — если это вообще не строка.
Один и тот же вызов strncpy требовал ручного чтения контекста: строка это или бинарное поле, нужен ли ноль, нужен ли padding. 362 раза, и каждый раз разное решение.
В вашей кодовой базе strncpy, скорее всего, всё ещё живёт как безопасный вариант. Это не баг в трекере, это код, который надо перечитать. И главная работа будет не в замене функции, а в том, чтобы понять, что лежит в каждом буфере. Ядру на это понадобилось шесть лет и 70 человек — на API, который выглядел как безопасный десятилетиями.
🐧Обсудить в Чате Linux