From 02265644ce1c8e8771a379e2b91f74c1046fdd5d Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 22 Oct 2026 15:48:15 +0200 Subject: [PATCH] Record verified media index fixes and remaining QUERY audit --- doc/tasks.md | 85 ++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/doc/tasks.md b/doc/tasks.md index 6049f883..5936bb21 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -8,63 +8,62 @@ ma_copy_file проверяет существование/идентичность, сохраняет один regular-файл при ./ или hardlink; ссылки назначения отклоняются, копирование идёт через соседний temp с проверенными записью/close/publish. Общие примитивы lib/file_io используются также video, сохраняя публикацию видео только в completion. - ma_uuid возвращает ошибку RNG и обнуляет выход; media_index не записывает результат при отказе media/block UUID. + ma_uuid возвращает ошибку RNG и обнуляет выход; media_index не регистрирует блоки при отказе media/block UUID. ma_file_size и переменные вызывающего кода — int64_t; проверяются смещения, число блоков и размеры выделений. Обход передаёт ошибки, пропускает ссылки/reparse points, проверяет длину/глубину; Windows использует wide API. Контракты .h и service_lifecycle описывают синхронные отказы, лимит 16 до completion и отсутствие отката work при отмене. Неверные аргументы дают -1, closing/destroy — CANCELLED; повторный вход в destroy диагностируется и отклоняется. - Новый test_media_primitives проверяет сохранность при I/O/fdopen ошибках, RNG/seek без записей в БД, + Новый test_media_primitives проверяет сохранность при I/O/fdopen ошибках, RNG/seek без записей блоков в БД, sparse-размеры на границах 2/4 ГиБ, ошибки обхода, ссылки/глубину и ownership задач с внедрением ошибок. Все шесть тестов media_primitives/video/media_index/attachment_send/services/dm_worker прошли ASAN/UBSan с detect_leaks=1. Общий check.sh: 176/176 и proxy/burst/load. Windows runtime/сборка не проверялись: кросс-компилятора в окружении нет. Логи: /tmp/media-primitives-full-check-final.log, /tmp/media-primitives-final.log, /tmp/media-asan-test_*.log. -[ ] **media_index_commit: не обрезать длинный location** — воспроизведено 22.10.2026: - Реальный файл: полный путь 582 байта, относительный 550; commit возвращает 0, в БД сохраняется 511 байт. - media_base + location не указывает на файл; исходный файл остаётся целым (14 байт). - register_async допускает dest_path до 1023 байт, register_downloaded сохраняет location без обрезания. - Согласовать ограничения с читателями/удалением и описать их в .h; недопустимый путь отклонять до файловых изменений/INSERT. - Стенд /tmp/media-index-location-audit.c, лог /tmp/media-index-location-audit.log; реализация не менялась. +[+] **media_index: пути без обрезания и единая media_base** — исправлено 22.10.2026: + Общие location/path проверяют границу базы, компоненты и пределы UTF-8 путей (1024/512 с NUL). + Путь в 550 байт полностью сохраняется, читается и удаляется. Проверки предшествуют файловой подготовке. + Выдача использует UTF-8 file_io; загрузчик проверяет общую базу, stop/start сохраняет выбранную базу БД. + Писатели, backfill, выдача и удаление используют один формат; контракты находятся в media_index.h. -[ ] **media_index: согласовать location и media_base у писателей и читателей** — воспроизведено 22.10.2026: - commit принимает абсолютный dest_path вне media_base и сохраняет его как location, возвращая 0. - media_delivery и delete_channel всегда строят media_base + '/' + location: выдача открывает неверный путь, - удаление возвращает 0 и стирает строку БД, хотя исходный файл остаётся на диске. - Нормализация завершающих '/' различается у commit (один), загрузчика (ни одного) и удаления (все). - Определить единый контракт относительного location/принадлежности базе, общую проверку и поведение ошибок; отразить в .h. - Подтверждены commit=0, resolved_size=-1, delete=0, actual_after=14, rows_after=0; лог /tmp/media-index-location-audit.log. +[+] **media_index_commit: атомарная регистрация и проверяемые повторы** — исправлено 22.10.2026: + Единый commit регистрирует весь авторский/скачанный файл через SAVEPOINT; key=NULL означает скачанный файл. + Проверяются геометрия/массивы, bind/step/finalize и управление транзакцией. + Ошибка второго блока откатывает оба пути регистрации; обычная ошибка сохраняет внешнюю транзакцию. + SQLite может сама откатить её целиком — это обнаруживается и диагностируется. + Совпадающий повтор сохраняет node_sign и timestamp; противоречащие метаданные дают ошибку без замены старых. + Файловые изменения worker не входят в SQL-атомарность. -[ ] **media_index_commit: исключить частичную регистрацию файла** — воспроизведено 22.10.2026: - Два блока; SQLite-trigger отклоняет INSERT chunk=1. commit возвращает -1, но строка chunk=0 остаётся в БД. - register_async в этом случае вернёт result=NULL и освободит идентификаторы подготовленного результата. - Обеспечить атомарность регистрации всех блоков с учётом внешней транзакции и описать гарантии .h. - Лог /tmp/media-index-location-audit.log: second-block-failure commit=-1 rows_remaining=1. - Уточнение плана: гарантия относится к БД, не к уже выполненному копированию worker. - SAVEPOINT сохраняет внешнюю транзакцию при локальных ошибках; RAISE(ROLLBACK) уничтожает и транзакцию, и savepoint. - Повтор скачанного блока не должен затирать подписанную запись автора нулевой node_sign; - отличающиеся chat_id/location сейчас также молча игнорируются с возвратом 0 — конфликт надо диагностировать. - Дополнительные проверки: /tmp/media-index-plan-review.c, /tmp/media-index-plan-review.log. +[+] **Удаление канала: дождаться исходящих медиа и учесть незавершённые файлы** — исправлено 22.10.2026: + Канал ждёт свои video/register completions; новые исходящие задачи отклоняются до завершения удаления. + Последний completion продолжает удаление. Подготовленные ожидающие отправки не становятся новыми сообщениями. + Контекст остаётся у владельца во время синхронного MSG_SUBMITTED; повторный вход обработчика проверен. + До worker путь учитывается в media_preparations; успешный commit снимает запись в той же транзакции. + После ошибки хеширования/отмены опубликованная копия остаётся известна для очистки канала. + Проверены две ожидающие задачи, повтор удаления, создание того же channel_id и удаление из обработчика события. -[ ] **Удаление канала: поздний completion повторно регистрирует медиа** — проверка плана 22.10.2026: - Стенд запускает register_async(copy=0), очищает media_files канала до обработки completion и затем обрабатывает uasync: - delete_channel=0, rows_before_completion=0, callback err=0, rows_after_completion=1. - mi_reg_done выполняет commit раньше on_media_registered, где проверяется наличие db_sync канала. - media_delivery_cancel_channel отменяет downloads/streams/relay, но не исходящие задачи регистрации. - Согласовать завершение подготовки с удалением канала до commit; учесть повторное создание того же channel_id - и отдельно определить судьбу файлов, которые worker успел опубликовать. Проверка только наличия канала недостаточна. - Реализация не менялась; стенд /tmp/media-index-plan-review.c, лог /tmp/media-index-plan-review.log. +[+] **media_index_delete_channel: ошибки и повторяемая частичная очистка** — исправлено 22.10.2026: + Полный снимок и проверка путей предшествуют удалению; внешняя транзакция отклоняется. + Общие файлы других каналов сохраняются; ENOENT считается успехом. + SQL/файловые ошибки возвращают -1, записи неочищенных путей сохраняются для повтора. + Проверен отказ DELETE после unlink: повтор завершает очистку без восстановления файла. + Очистка включает media_preparations; ошибки очистки и удаление метаданных канала сообщаются раздельно. -[ ] **media_index_delete_channel: возвращать реальные ошибки удаления** — воспроизведено 22.10.2026: - После DROP TABLE media_files delete_channel возвращает 0 при SQLite-ошибке no such table. - Ошибки prepare/step не диагностируются; ошибки remove дают WARN, но строки всё равно удаляются, возврат 0. - Определить поведение при частичном файловом удалении, проверить SQL и построение путей, описать .h. - Лог /tmp/media-index-location-audit.log: absent-table delete=0; outside-base removed=0 rows=1. +[+] **media_index_init: ошибки всех индексов доходят до запуска чата** — исправлено 22.10.2026: + Проверяется каждый CREATE INDEX. Ошибка прерывает chat_core_init с освобождением собственных ресурсов; + общая БД ядра сохраняется. Проверены запрет каждого индекса и успешный повтор старта после снятия запрета. + Дополнительно исправлены дубликат start (отказ без callback) и доступ к dl после синхронного завершения QUERY. + Тесты используют реальную схему БД и проверяют новый контракт владения. + Итог: check.sh — 177/177, proxy/burst/load PASS, 159с. + Девять тестов index_regressions/index/delivery_download/download_timeout/services/delivery_full/delivery_chat/attachment_send/video + прошли ASAN/UBSan с detect_leaks=1. Windows runtime/сборка не проверялись: кросс-компилятора нет. + Логи: /tmp/media-index-full-check-final.log, /tmp/media-index-final-test_media_index_regressions.log, + /tmp/media-index-asan-test_*.log. Новый тест: tests/test_media_index_regressions.c. -[ ] **media_index_init: проверять создание всех индексов** — воспроизведено 22.10.2026: - SQLite-authorizer запрещает SQLITE_CREATE_INDEX: init возвращает 0 и пишет table+indices created, - хотя таблица создана без единого индекса, включая UNIQUE(block_id). Ошибки пяти sqlite3_exec игнорируются. - Проверять результат каждого CREATE INDEX и возвращать ошибку с точной диагностикой вместо ложного успеха. - Лог /tmp/media-index-location-audit.log: denied-indices init=0 actual_indices=0. +[ ] **media_delivery QUERY: согласовать число блоков и проверку длины** — статическая проверка 22.10.2026: + md_handle_query обрезает num_blocks до 64, хотя регистрация/загрузчик допускают больше блоков. + Обработчик проверяет только размер заголовка и читает block_id без проверки len >= header + count*16. + Отдельно воспроизвести запрос на 65 блоков и усечённый пакет; согласовать лимит/разбиение запросов и валидацию. + Это отдельная задача протокола; текущие исправления регистрации и удаления её не меняют. [+] **test_stream_service: убрать зависимость bootstrap-проверки от гонки TCP-handshake** — исправлено 22.10.2026: Падение на строке 409: REINIT=0 при probes=1/subflows=1/failures=0 и доставленной первой пачке.