Record instance lifecycle fixes, contracts and sanitizer audit evidence

This commit is contained in:
evgeny committed 2026-10-26 09:08:42 +01:00
1 parent 4219d5ce1d
commit 8640b45e99
1 file changed
+99
+99
View File
@@ -0,0 +1,99 @@
Аудит utun_instance — 26.10.2026
Объём
Полностью прочитаны utun_instance.c/.h и прежний utun_instance_doc.md; сверены
вызовы конструкторов/start/stop/reload из CLI/встраивания и связанные механизмы
ETCP/NCD/STCP, sockets, logger, очередей, SQLite и независимых сервисов.
Заголовок и документ переписаны по фактическому коду. Core-разделы
doc/service_lifecycle.md согласованы; весь поперечный документ остаётся [~].
Это не полный аудит реализаций chat/call/radio/stream или GUI/Android.
Исправления
- Activity/peer-sleep подписки удерживают снятые записи до выхода из внешней
рассылки. Безопасны удаление себя/соседа, вложенное событие и добавление новой
подписки. Повтор fn+arg не дублируется; более новая эффективная activity
отменяет остаток старой рассылки. OOM обеих подписок логируется.
- Конструкторы проверяют UASYNC/config/path до побочных действий; общий путь
создания освобождает частичные ресурсы, сохраняя caller config при отказе.
Проверяются crypto derivation, запись/close временного файла, создание каталогов
и индекс сетей. Старый TCP-реестр индексируется по node_id, а не указателю link.
- Выбранный путь общего logger копируется в постоянный буфер; освобождение config
больше не оставляет заимствованную строку в logger. Уже открытый файловый logger
сохраняет первый путь при создании/reload другого instance.
- Reload готовит config/firewall/networks до изменения ресурсов. Смена владельцев
(в том числе db_path, control, TUN/NAT/proxy), подсетей или automatic server-конфига
пересоздаёт ядро с прежними core/UTUN/chat/running. Повторные имена server также
выбирают полный путь, сохраняя отдельные секции parser без неоднозначного matching.
- Manual reload сравнивает все server-параметры и IPv6 scope по конфигурации,
сохраняя неизменённые sockets/ephemeral ports. TCP listener закрывается вместе
с правильной TCP-моделью; UDP создаётся/удаляется своим API. Устранён лог через
освобождённое имя. Probe и endpoints других владельцев не удаляются по отсутствию
server-секции. Конфигурационные clients обновляются также без UTUN; неизменённые
handles/таймеры сохраняются, копии не ссылаются на освобождённый config.
- Destroy обходит sockets/connections от свежей головы после callbacks,
освобождает старые TCP queue entries и оставшиеся transport-подписки.
Повторный destroy/start/reload при разрушении отклоняется; SQLite close ошибки
видны, BUSY завершается close_v2 до финализации заимствованных SQL-объектов.
- Три headless bind разбираются одинаково: IPv4 literal, полный decimal port
0..65535. Port=0 выбирает ОС; плохое значение не открывает порт по умолчанию.
Отказ listener не фатален для чата, частичный контекст очищается.
- Call/radio headless stop освобождает контекст/кодеки, снимает клиентов с UASYNC
и отменяет cleanup/mix таймеры. Их отказы при старте дают rollback.
- UBSan нашёл невыровненный PCM после 11-байтового headless заголовка и uint64_t
hop-list в radio_recv. Оба читаются через выровненное хранилище; тест рации также
использует memcpy вместо int16_t* к невыровненному payload. Wire не менялся.
- Из заголовка удалено объявление несуществующего utun_instance_run; poll принадлежит
caller. Уточнены владение, состояния, ошибки init/reload, подписки и диагностика.
Контракты и ограничения
Все lifecycle операции выполняются в потоке своего UASYNC, stop/destroy/reload —
вне callbacks останавливаемых модулей. UASYNC принадлежит caller и живёт до конца
очистки. Core start при отказе сохраняет подготовленные ресурсы для retry/destroy;
init при отказе позднего сервиса сохраняет ранее запущенные сервисы.
Create уже выполняет I/O и создаёт listeners/SQLite/router/proxy/monitoring.
Create_from_str требует временного файла /tmp и не является чистым buffer parser.
Logger общий для процесса; его изменения и config updater не входят в транзакцию reload.
Partial reload не атомарен: отказ endpoint сохраняет новый config и отсутствие
endpoint для следующей попытки. Подготовка clients при ошибке сохраняет прежние
самостоятельные handles. Full reload возвращает NULL, если новое ядро не удалось
создать/запустить после уничтожения старого; caller использует возвращённый указатель.
Порядок списков/padding модели может консервативно выбрать restart. IPv6 selector
temporary/permanent меняет адрес в модели при разрешении, поэтому повторный reload
может консервативно пересоздать такой endpoint.
Caller завершает borrowed statements/backups; close_v2 не разрешает использовать
уничтоженный instance. Живые ресурсы в diagnose_leaks сами по себе не доказывают утечку.
Отменённые heap-таймеры UASYNC освобождаются при следующем poll, а pool cache — при
уничтожении UASYNC; тест сверяет active/counters и общий баланс после обоих шагов.
Проверки
- Полная обычная сборка PASS: /tmp/utun-instance-audit-build-final.log.
- Первый полный check.sh: 196/196 PASS, 0 failed/0 skipped; proxy9/9, burst1/1,
load8/8, 134217728 байт, 189с; /tmp/utun-instance-audit-final-check.log.
Он предшествовал последней правке выравнивания radio hop-list.
- Профиль после исправлений: test_instance_contract, test_services, test_ncd_config,
test_tun_route, test_etcp_transport, test_stcp, test_node_conn_direct,
test_call_headless, test_radio_headless PASS; три изменённых адресных теста
повторены в /tmp/utun-instance-audit-final-test_*.log.
- Новый test_instance_contract проверяет nested callbacks/OOM, constructor ownership,
правильный TCP queue index, неизменённые ephemeral endpoints, malformed config,
отказ network queue/create endpoint с retry, UDP/TCP замену и удаление listener,
duplicate server names, full reload с сохранением stopped/core-only состояния,
SQLite BUSY/finalize, другой UASYNC, db_path restart, recursive mkdir и жизнь
logger path после освобождения config. Headless: три port=0, реальные TCP-клиенты,
stop/start с сохранением SQLite, три timer faults и malformed binds.
- ASAN/UBSan/LSan 11/11 PASS, detect_leaks=1, halt_on_error=1:
те же девять instance/transport/headless тестов плюс config_parser/config_updater.
Итог: /tmp/utun-instance-audit-asan-results-complete.log; отдельные логи
/tmp/utun-instance-audit-asan-complete-test_*.log.
Отдельная копия /tmp/utun-config-instance-asan-20261026, все lib/src/Opus
инструментированы согласованно. Встроенный Opus не перекрывает CFLAGS в этой
тестовой копии; рабочая normal-сборка с sanitizer-объектами не смешивалась.
Сборки: /tmp/utun-instance-audit-asan-build.log,
/tmp/utun-instance-audit-asan-core-final.log и ...-asan-tests-build.log.
Ранние наборы 9/11 и 10/11 выявили описанные alignment defects; окончательный
набор после исправления обеих причин полностью PASS.
- git diff --check PASS. Нативные Windows/FreeBSD сборки/runtime, GUI/Android и
аппаратные TUN/media в этом этапе не запускались; Linux TUN lifecycle проверен mock-тестом.
Окончательный штатный check.sh после последней правки: результат дописывается ниже.