Files
utun2/doc/dm_audit_findings.txt
T

383 lines
37 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
DM — аудит документации и контрактов, 26.10.2026
База: /home/user/utun2, HEAD 03b050949cf36cc4868324be94a54eaddfdd494c.
Задание: /home/user/utun-doc-audit-checklist.txt, раздел src/dm/ и связанные документы.
1. Объём и статус
Полностью прочитаны dm_core.c/.h, dm_crypto.c/.h и dm_history.c/.h, doc/dm_arch.md,
doc/pm.txt и doc/pm_invites.md. Просмотрены заголовки media/mailbox owners, lifecycle
в utun_instance и участок media_forget_prepare/committed. Это не полный аудит этих owners.
dm_crypto.h [V]; dm_core.h/dm_history.h/doc/dm_arch.md [~].
dm_mailbox.h/dm_mailbox_media.h/dm_media.h/dm_media_priv.h сохраняют [ ].
doc/pm_invites.md сохраняет [~]; doc/pm.txt [ ]: нормативные требования прочитаны,
но соответствие всей доставки и хранения пока не проверено.
Уточнены контракты nonce, native-endian wire/длин, lifecycle, commit исходящей задачи,
JSON и локального удаления/поколений. В pm_invites исправлен формат события результата:
36 байт с generation вместо прежних 28. Платформенные реализации целиком не проверялись.
2. Исходный дефект: ошибка загрузки сбрасывает счётчики существующей беседы
dm_conv_load возвращает -1 при отсутствии строки и при ошибках prepare/step,
повреждённых ключах либо отказе X25519. dm_start проверяет только ==0, а иначе
обнуляет dm_conv, заполняет ключи и сохраняет через dm_conv_save.
ON CONFLICT обновляет last_out_seq/last_in_seq/last_ts из обнулённой структуры.
Ошибка чтения тем самым превращается в успешную запись с потерей счётчиков.
Проверка использует настоящие utun_core/chat_service, SQLite и OpenSSL, отдельные
БД в /tmp, штатные dm_start/dm_send/dm_accept_message. Исходные сообщения принимаются
обычным публичным API. SQLite authorizer однократно отказывает в чтении
dm_conversations.peer_node_id; последующие операции разрешены. Production-файлы,
архивы и объекты для воспроизведения не подменялись.
Положительный контроль: повторный dm_start без отказа сохраняет out=1,in=2.
При одном SQLITE_DENY: dm_conv_load пишет ERROR с точной причиной, затем dm_start
пишет INFO started, возвращает 0; out=1->0,in=2->0, обе строки dm_messages остаются.
Проверка ожидаемого отказа/сохранности даёт FAIL, exit2; tracked allocations0->0.
Существующей диагностики вместе с журналом инъекции и SQL-снимком достаточно
для однозначного вывода: это ошибка ветвления, не ошибка расшифровки или транспорта.
Последствия: пока исходящая строка seq=1 сохранена, новая отправка того же номера
будет конфликтовать с историей. После локального удаления история очищается,
а сброшенный счётчик сохраняется; повтор seq при неизменном ключе воспроизведёт
детерминированный nonce. Это вывод из кода, повторная отправка после сбоя в стенде
не выполнялась. Раскрытие содержимого/эксплуатация не проверялись.
В dm_accept_message и dm_invite_trampoline также смешаны отсутствие и ошибка
dm_conv_load; их отказные сценарии в этом этапе отдельно не воспроизводились.
Простой план исправления: выделить результаты FOUND/NOT_FOUND/ERROR для загрузки;
считать NOT_FOUND только завершённый SELECT без строки, ошибки логировать и
передавать без UPSERT/события успеха. Просмотреть все callers, включая dm_media;
при найденной беседе не обновлять seq из пустой структуры. Регрессии должны
проверить prepare/step/короткие ключи/crypto, сохранность полей и generation/hidden,
повторный запуск, успешное создание отсутствующей беседы и нормальное продолжение seq.
Новый формат протокола или БД для исправления не требуется.
3. Проверки и артефакты первоначального аудита, до исправления
Сборка штатных шести целей через tests/Makefile — PASS.
test_dm/test_dm_history/test_dm_e2e/test_dm_invite/test_dm_media/test_dm_worker:6/6 PASS.
Полные логи прочитаны; ERROR в штатных отрицательных проверках ожидаемы.
Worker:24 запуска,49 heartbeat,max_gap11.3мс. Media:phase9 PASS.
Эти тесты не покрывают подтверждённый отказ загрузки беседы.
/tmp/dm-audit-baseline-build.log
/tmp/dm-audit-baseline-results.log
/tmp/dm-audit-baseline-test_dm{,_history,_e2e,_invite,_media,_worker}.log
/tmp/dm-audit-load-failure.c и /tmp/dm-audit-load-failure.mk
/tmp/dm-audit-load-failure-build.log
/tmp/dm-audit-load-failure.log (контроль PASS, сохранность при отказе FAIL, exit2)
Первый запуск стенда в sandbox остановился до DM на запрете netlink-сокета.
Окончательные стенд и штатные тесты запущены с разрешением вне sandbox;
сетевые настройки хоста не менялись. Пользовательская БД не использовалась.
Рабочий алгоритм, протокол, БД и штатные тесты не менялись: только документы/комментарии.
Новые полный check.sh, ASAN/UBSan/LSan, GUI/Android/Windows/FreeBSD не запускались.
По AGENTS.md:10 аудит остановлен на подтверждённом дефекте до его исправления;
открытая задача внесена в doc/tasks.md. Коммит/push не выполнялись.
4. Исправление по запросу пользователя — 26.10.2026
dm_conv_load теперь возвращает FOUND/NOT_FOUND/ERROR. Только SQLITE_DONE без строки
и с успешным finalize означает NOT_FOUND; SQL-ошибки prepare/bind/step/finalize,
короткие ключи и отказ X25519 означают ERROR. Полная структура выдаётся только
после успешного завершения загрузки/вывода ключа. Лог содержит conv/rc/SQL-причину,
успешная загрузка с seq доступна в TRACE, отсутствие записи — DEBUG.
Проверены все5 callers: dm_start и dm_accept_message возвращают ошибку без
создания/сохранения/открытия беседы, dm_invite_trampoline завершает запрос
DM_INVITE_START_ERROR без повторного dm_start; dm_send и JSON требуют FOUND.
В dm_start также перестала игнорироваться ошибка сохранения выбранной области.
Медиа не вызывает dm_conv_load и не создаёт беседу вместо ошибочной загрузки:
dm_send_file отклоняет ошибки чтения/ключей до регистрации worker/файлов.
Протокол и формат БД не менялись.
Постоянная Linux-регрессия test_dm_load включена в check_PROGRAMS.
35 комбинаций5 callers×7 отказов для видимой беседы, ещё35 после локального удаления,
4 отказа отдельной media-подготовки и5 отказов открытия отсутствующей беседы:79 PASS.
Отказы:prepare/bind/step/finalize,короткие X25519/Ed25519 BLOB,EVP_PKEY_derive.
Проверяются SHA256 всех полей7 DM-таблиц,sqlite3_total_changes,autocommit,
отсутствие событий успеха и неизменённый буфер квитанции при отказе приёма.
Нормальные контроли:создание отсутствующей беседы,повторное открытие после restart,
продолжение исходящего seq1->2 и приём впервые доставленного seq1 после seq2.
Запрос invite проверяется на настоящей собственной CHAT-группе; общая доставка
и создание беседы при первом входящем сообщении покрываются штатными E2E/media-тестами.
Новая регрессия с прежним dm_core.c из HEAD ожидаемо FAIL на первом prepare-отказе:
ошибка -> dm_start0,дополнительные SQL-write/CONV_UPDATED;cleanup allocations0->0.
Использовались отдельные /tmp/old-core.o и бинарник; рабочий архив не подменялся.
Первоначальный стенд с настоящим SQLITE_DENY теперь PASS:dm_start=-1,out1->1,in2->2,
две строки истории сохранены,allocations0->0. Оба контрольных лога прочитаны полностью.
Сборка Linux PASS; DM-профиль test_dm_load/dm/history/e2e/invite/media/worker7/7 PASS.
ASAN/UBSan/LSan тот же профиль7/7 PASS с detect_leaks=1/halt_on_error=1.
Отдельная копия /tmp/utun-dm-load-sanitizers:новая сборка core/libuasync/Opus
с согласованными -fsanitize=address,undefined,без смешивания обычных объектов.
dm_core.c,test_dm_load.c,tests/Makefile.am побайтно совпадают с рабочими.
Проверены все sanitizer-логи:нет отчётов ASAN/UBSan/LSan;test_dm_load allocations0->0.
Первый полный check.sh:202 passed,1 failed,0 skipped (203 total).
Отказ test_chat_join_e2e:happy A!=C,J не декодировал приглашение,потом A/C не нашли J;
degraded и invalid-key PASS. Отдельный диагностический повтор3/3 PASS.
Код теста создаёт link.txt до записи/закрытия;читатель ждёт только access(F_OK).
Это возможная гонка тестовой публикации,но конкретная причина исходного отказа
не доказана без размеров/результатов чтения. Отдельная задача в doc/tasks.md;
production JOIN и критерии/код теста не менялись,первый отказ сохранён.
Окончательный повтор полного check.sh:203 passed,0 failed,0 skipped;exit0,175с.
Интеграции proxy9/9,burst1/1,load8/8 PASS,134217728 проверенных байт.
В этом прогоне новый test_dm_load PASS;код после профильных проверок не менялся.
Повторный успех не закрывает отдельную задачу диагностики исходного отказа JOIN.
Логи исправления:
/tmp/dm-load-fix-build.log (окончательная сборка PASS)
/tmp/dm-load-fix-profile-results.log и /tmp/dm-load-fix-test_dm*.log
/tmp/dm-load-fix-controls-results.log и /tmp/dm-load-fix-control-*.log
/tmp/dm-load-fix-negative-build.log и /tmp/dm-load-fix-original-build.log
/tmp/dm-load-fix-sanitizers-build.log,/tmp/dm-load-fix-sanitizers-results.log,
/tmp/dm-load-fix-sanitizers-test_dm*.log,/tmp/dm-load-fix-final-verification.log
/tmp/dm-load-fix-full-check-first.log,/tmp/dm-load-fix-join-first.log,/tmp/dm-load-fix-join-repeat.log
/tmp/dm-load-fix-full-check.log,/tmp/dm-load-fix-netns.log,/tmp/dm-load-fix-repeat-netns.log
Полный набор запускается в отдельном IPv6 network namespace без изменения сети хоста.
Начальные ошибки подготовки sanitizer-копии (недостающие generated auxiliary files/
etcpmon header и ограничение LSan в sandbox) устранены до успешной сборки/прогона.
В первом native build не хватало openssl/evp.h в новом тесте;добавлен до успешной сборки.
GUI/Android/Windows/FreeBSD не запускались;регрессия с linker wrappers — Linux.
Дефект счётчиков исправлен;исходные частичные отметки аудита остальных DM owners сохраняются.
Коммит/push не выполнялись.
5. Исходный отказ mailbox/media — 26.10.2026: transient SQL становится постоянным отказом M
Прочитаны полностью dm_mailbox.c,dm_mailbox_media.c,dm_media.c и четыре заголовка,
связанные file_transfer/media_async контракты,lifecycle instance и штатный test_dm_media.
Уточнены uasync/ownership/lifecycle,семантика принятия PUT,транзакция регистрации media,
предусловия размеров control,ограничение рассылки до64 S на группу и SQL-helper ownership.
Четыре новых заголовка отмечаются[~]:чтение завершено,но полный аудит контрактов/отказов
и документация media API не завершены. Прежние core/history/dm_arch[~],crypto[V] сохраняются.
Дефект в dm_custody_store:результат SELECT COALESCE(sum(cipher_size),0) FROM dm_custody
при любом rc!=SQLITE_ROW превращается в used=UINT64_MAX. Следующая ветка used>quota
выдаёт DM_MEDIA_REJECT reason1,то есть утверждает реальное переполнение квоты.
Оригинальная причина SQL не логируется;WARN показывает фиктивный used18446744073709551615.
dm_mailbox_media_recv на S сохраняет released=1 и holder=0. dm_job_storage исключает
все прежние назначения через NOT IN(SELECT node_id FROM dm_media_holders WHERE id=?),
включая released. Поэтому повторные STORE на этом M для UUID больше не возникают.
Доказательство:/tmp/dm-quota-audit.c/.mk,временный вариант штатного test_dm_media.
Настоящие четыре utun/chat ядра A/B/S/M,разные БД,подписанные channel/member/admin-блоки,
реальные UDP-транспорты и file_transfer. Сначала штатная прямая доставка и прежние
проверки rollback/реальной квоты;затем B останавливается,A отправляет новое вложение.
Прикладной алгоритм,архивы,production-объекты и штатный тест не подменялись.
Linker-wrapper однократно возвращает SQLITE_IOERR только для used-space SELECT в БД M.
В обеих проверках настроено1024МиБ,текущая custody пуста;ciphertext запрашивает98385байт.
Контроль без отказа:назначение M->custody reserved->файл сохранён->STORED на S.
Через16 календарных секунд тестовых часов:ready1,released0,waiting0,holders1,used98385;
phase9 PASS,exit0,allocations0->0.
Fault:SQLITE_IOERR->quota refused usedUINT64_MAX requested98385 quota1073741824,
затем storage refused reason1 на S. Через16с:ready0,released1,waiting1,holders1,used0;
quota-запрос STORE выполнен только один раз (финальный диагностический SELECT в счётчик не включён).
phase4 ожидаемо FAIL,exit1,allocations0->0. После однократного отказа SQLite работает;
возобновления назначения нет. Persistent-исключение после restart следует из таблицы/SQL,
отдельный restart в этом стенде не выполнялся.
Логи:/tmp/dm-quota-audit-build.log,/tmp/dm-quota-audit-results.log,
/tmp/dm-quota-audit-control.log и /tmp/dm-quota-audit-fault.log.
Ключевые строки всех переходов сохранены в /tmp/dm-quota-audit-diagnostics.log.
В baseline protocol_checks ожидаемы отдельный SQL-trigger rollback и настоящий
quota-отказ2МиБ при квоте1МиБ:они происходят до включения fault и не являются новым дефектом.
Работающие transport/media callbacks и SQL-снимки однозначно показывают механизм;
production-диагностика должна дополнительно различать SQL-ошибку и настоящую квоту.
Простое исправление:проверять результат чтения занятого места отдельно,логировать
ошибки SQL с rc/причиной и возвращаться без REJECT. Сохранённый holder/stored0 на S
уже обеспечивает повтор STORE через существующий таймер. Реально недостаточная
квота сохраняет нынешний REJECT,выбор другого M и учёт всех назначений.
Также проверить bind/finalize,не выдавать operational-ошибку за quota refusal.
Постоянная регрессия:однократные SQL-отказы не исключают свободный M,последующий
STORE сохраняет ciphertext;реальная квота по-прежнему отклоняет запрос до загрузки.
Новый протокол/формат БД/специальный control для retry не требуется.
По AGENTS.md:10 аудит остановлен до исправления;открытая задача в doc/tasks.md.
В этом этапе изменены только комментарии/документы/отметки;исправление dm_conv_load
и новая постоянная регрессия из предыдущего этапа сохранены. Новые fullcheck/ASAN/UBSan/LSan,
GUI/Android/Windows/FreeBSD не запускались;прежние203/203 и sanitizer7/7 относятся
к предыдущему исправлению,а не к новому отказу custody. Коммит/push не выполнялись.
6. Исправление quota-admission — 26.10.2026
По запросу пользователя dm_custody_store проверяет чтение занятого места и finalize
до сравнения с квотой. Ошибка prepare уже возвращалась без ответа;теперь ошибка step,
неожиданный SQLITE_DONE и ошибка finalize также прекращают STORE без REJECT/регистрации.
Лог step/finalize содержит rc,SQL-причину и указание на сохранённый повтор STORE.
Прежнее назначение M остаётся на S;его штатный таймер повторяет STORE. Настоящий
недостаток квоты по-прежнему выдаёт reason1. У агрегатного SELECT нет bind-параметров.
Протокол,формат БД и алгоритм назначения S не менялись.
Постоянный test_dm_media расширен fault wrappers только для Linux:
- Отдельные prepare/step/finalize/неожиданный DONE проверяют один отказ за вызов,
отсутствие REJECT/STORED,отсутствие изменений SQL в S/M,пустые custody/tombstones,
autocommit. Достаточная квота настроена1024МиБ;отказ не заменяется успешной регистрацией.
- Настоящее превышение квоты требует ровно один REJECT без STORED/регистрации custody.
- Сетевой сценарий использует прежние4 ядра,подписанные роли,настоящие UDP/router/transfer.
После отключения B первые3 STORE получают разные SQL-ошибки на M:prepare,step,finalize.
Четвёртый STORE сохраняет файл на том же M;REJECT0,STORED1,одно назначение,released0.
Последующие штатные проверки перезапуска S/M при выключенном A,точного файла у B,
квитанций,удаления промежуточной копии/тела S,поздних STORE/STORED и TTL сохранены.
Исходные4 сбоя проверяют обработчик после router,сетевой retry идёт обычным транспортом.
Нативный и sanitizer-профили7/7 PASS:test_dm_load/dm/history/e2e/invite/media/worker.
В test_dm_media phase9 PASS,allocations0->0;в native/sanitizer одинаковая последовательность
hits3,STORE4,REJECT0,STORED1,holders1. ASAN/UBSan/LSan7/7 PASS,detect_leaks=1,
halt_on_error=1;ядро,libuasync и встроенный Opus собраны с одинаковыми sanitizer-флагами.
Использована отдельная копия /tmp/utun-dm-quota-sanitizers;обычные объекты не подменялись.
Побайтно сверены dm_media.c/test_dm_media.c/tests/Makefile.am и прежние dm_core.c/test_dm_load.c.
Контроли:
- Новый test_dm_media с dm_media.c из HEAD ожидаемо FAIL,exit1:step-отказ даёт ложный
REJECT,который ловит новая проверка. allocations0->0. Старый модуль собран отдельным
объектом и включён в отдельный бинарник;рабочий libutun.a не подменялся.
- Исходный /tmp/dm-quota-audit.c с одним SQLITE_IOERR и исправленным core:phase9 PASS,exit0.
- test_dm_media без DM_QUOTA_FAULT_INJECTION:штатный сценарий phase9 PASS,exit0.
Это Linux-компиляция без wrappers;runtime других ОС не проверялся.
Все3 контроля восстанавливают tracked allocations до0. Полные логи изменённого
media-теста/native/sanitizer/контролей прочитаны;ожидаемые ERROR относятся к инъекциям.
Артефакты:
/tmp/dm-quota-fix-build.log
/tmp/dm-quota-fix-profile-results.log,/tmp/dm-quota-fix-test_dm*.log
/tmp/dm-quota-fix-sanitizers-build.log,/tmp/dm-quota-fix-sanitizers-results.log,
/tmp/dm-quota-fix-sanitizers-test_dm*.log
/tmp/dm-quota-fix-controls-build.log,/tmp/dm-quota-fix-controls-results.log,
/tmp/dm-quota-fix-control-{test_dm_media_old,dm-quota-fixed-original,test_dm_media_no_injection}.log
/tmp/dm-quota-fix-final-verification.log
/tmp/dm-quota-fix-full-check.log,/tmp/dm-quota-fix-netns.log
Полный check.sh203/203 PASS,0 failed/0 skipped;proxy9/9,burst1/1,load8/8 PASS,
134217728 проверенных байт,exit0,176с. Этот прогон включает новую fault/retry-проверку media.
Набор выполнен в отдельном IPv6 network namespace;сеть хоста не менялась.
Первый сборочный запуск отдельного negative-control не включал test_clock.o в линковку;
временная make-цель исправлена до контрольных прогонов. Основная сборка/код от этого не менялись.
Документация обновлена,задача quota-admission закрыта. Остальные отметки аудита DM остаются
частичными;GUI/Android/Windows/FreeBSD не запускались. Коммит/push не выполнялись.
7. Commit/rebase/push по запросу пользователя — 26.10.2026
Все накопленные изменения DM сохранены в2ae1990d. Fetch обнаружил8 новых коммитов
origin/master поверх03b05094:изменения headless PCM,документации звонков и их проверок.
Rebase на03be46c3 завершён с единственным конфликтом doc/tasks.md:сохранены обе
полные группы задач. tests/Makefile.am объединился автоматически,цели test_dm_load,
quota wrappers test_dm_media и upstream test_call_headless_queue присутствуют.
DM .c/.h и обе новые/расширенные регрессии побайтно сохранены относительно исходного коммита.
После rebase коммит стал b6588d059455ed430c902a325af7d010f15f3475.
Нативная сборка PASS;новый полный check.sh204/204 PASS,0 failed/0 skipped,
proxy9/9,burst1/1,load8/8 PASS,134217728 байт,exit0,175с. Включён новый upstream
test_call_headless_queue (11/11) и все DM-регрессии. Сеть — отдельный IPv6 namespace.
Push origin master:03be46c3..b6588d05 PASS,без force. git ls-remote подтвердил hash,
HEAD==origin/master,рабочее дерево после push было чистым.
Логи:/tmp/dm-audit-rebase-build.log,/tmp/dm-audit-rebase-full-check.log,
/tmp/dm-audit-rebase-netns.log. Санитайзеры после rebase заново не запускались;
исходные DM-файлы по сравнению с прошедшим sanitizer-профилем не менялись.
8. Продолжение: UTF-8 имя повреждается при построении беседы
Продолжены сверка core/history,передачи поколения и путей из attachment_send,
участков headless/GUI/JNI вызывающих функций. Это чтение кода,не аппаратная проверка UI.
Уточнён dm_send_file:0 означает вызов submit,который вправе синхронно вызвать callback
ошибки;результат подготовки сообщается событием. Это исправление описания возврата.
Новый подтверждённый дефект:dm_conv.peer_name[64],snprintf в dm_start/dm_conv_load
режут имя по63байтам,без проверки границы UTF-8. json_escape передаёт получившиеся
байты в JSON без проверки/исправления. Корректное входное имя тем самым повреждается
в SQLite,а dm_list_conversations_json возвращает0 с некорректным UTF-8 JSON.
dm_start_req допускает до127байт имени;отсутствует предусловие ASCII/<=63байт.
Стенд:/tmp/dm-utf8-audit.c/.mk. Настоящие core/chat_service/SQLite/X25519,
отдельные ключи для трёх собеседников,новая БД/tmp;публичные dm_start/list API.
Валидные входы:ASCII63байта;31×«Я»=62байта;32×«Я»=64байта.
Контроли ASCII63/UTF8_62 дают корректный UTF-8 JSON. UTF8_64 сохраняется как63байта,
последний байт0xd0 без продолжения;start=0,list=0. Строгий Python decode JSON
даёт invalid continuation byte на позиции537;проверка exit2. SQL-readonly-снимок
подтверждает тот же обрыв в сохранённом peer_name,tail_hex=afd0afd0afd0afd0.
Tracked allocations0->0;собственно C-стенд exit0,отказ обнаруживает независимый валидатор.
Сам runtime-лог тоже содержит этот некорректный байт:валидатор читает диагностический
лог с replacement только для поиска ASCII-путей,но JSON и SQL BLOB проверяет строго.
Причина однозначна по точным входным/сохранённым длинам и байтам;это не ошибка JSON
парсера,шифрования или вывода терминала. Повторная загрузка имени через dm_conv_load
имеет то же побайтовое усечение;этот путь в новом стенде отдельно не запускался.
Простой план:определить единое ограничение имени и копировать только целые UTF-8
code points. Проверять входы и уже сохранённые некорректные строки с диагностикой;
увеличение массива само по себе не решает обрыв на новой границе.
Постоянные проверки:ASCII и2/3/4-байтовые символы до/на/за границей,SQL round-trip,
повторная загрузка и строгая декодируемость JSON. До выбора обработки уже повреждённых
имён (безопасное усечение/отказ) рабочая реализация не менялась.
Логи:/tmp/dm-utf8-audit-build.log,/tmp/dm-utf8-audit-runtime.log,
/tmp/dm-utf8-audit-validation.log;валидатор:/tmp/dm-utf8-audit-validate.py.
По AGENTS.md:10 дальнейший аудит остановлен,задача открыта в doc/tasks.md.
В продолжении только комментарии/документы,все текущие частичные отметки сохранены.
Предыдущий check204 проверял объединённые исправления,а не обработку нового имени;
новые sanitizer/GUI/Android/Windows/FreeBSD проверки не запускались.
9. Исправление UTF-8 имени собеседника
Предел имени явно задан DM_PEER_NAME_MAX=63 байта без NUL. Единый dm_copy_peer_name
сохраняет целые UTF-8 code points при dm_start, dm_conv_load, автосоздании во входящем
dm_accept_message и построении снимка бесед. Входящее имя из nodes сначала читается
в128байт, чтобы прежнее предварительное усечение в64байта не портило символ.
JSON нормализует как SQL peer_name,так и fallback из nodes при пустом имени.
Некорректная последовательность,overlong,surrogate,значение выше U+10FFFF или NUL
внутри SQL TEXT обрывают имя перед первым недопустимым code point. WARN содержит
conv_id,смещение и исходную длину;обычное усечение длинного имени отмечается DEBUG.
Чтение/снимок не исправляют SQL автоматически. Следующая штатная запись беседы
сохраняет уже нормализованное имя;формат БД/wire и счётчики сообщений не меняются.
Постоянный test_dm_names добавлен в штатный набор tests/Makefile.am:
68 случаев с реальными core/chat_service/SQLite и отдельными ключами собеседников.
ASCII0/1/62/63/64/127байт;границы2/3/4-байтовых символов до/на/за63байтами,
повторяющиеся символы,включая U+10FFFF;12 видов некорректных последовательностей
с пустым/непустым префиксом;SQL TEXT с NUL;кавычки/слеш/newline и кириллица.
Каждый случай проверяет точные SQL/JSON имена при создании,чтении повреждённого
сохранённого имени,load через чтение сообщений,load/save через dm_send и fallback.
total_changes и исходные SQL-байты подтверждают отсутствие скрытых записей при чтении.
Отдельно проверен restart с той же БД/идентичностью;allocations0->0.
Независимый строгий Python decode UTF-8 + json.loads проверил273 полных снимка,
9452 строки бесед и предел63байта на каждое имя;PASS в native и sanitizer сборках.
Контроль с прежним core:новая регрессия FAIL,exit1,на чтении длинного SQL-имени
после первых4 случаев (прежний JSON обходил предел);allocations0->0.
Исходный стенд раздела8 повторён на исправленном core:ASCII63/UTF8_62/UTF8_64 PASS,
32×«Я» сохраняются как62байта,строгий JSON всех3 снимков корректен,allocations0->0.
Исходные доказательства дефекта сохранены в прежних /tmp/dm-utf8-audit-*.log.
Нативная сборка PASS;DM-профиль8/8 PASS: names/load/crypto/history/e2e/invite/media/worker.
ASAN/UBSan/LSan8/8 PASS,detect_leaks=1,halt_on_error=1;отчётов о памяти/UB/утечках нет.
Изолированная копия /tmp/utun-dm-utf8-sanitizers синхронизирована с текущими исходниками,
включая upstream call_headless;ASAN/UBSan-ссылки проверены в core/libuasync/Opus.
Полный check.sh205/205 PASS,0 failed/0 skipped,proxy9/9,burst1/1,load8/8,
134217728байт,exit0,172с. Сеть — отдельный IPv6 namespace,сеть хоста не менялась.
Логи:/tmp/dm-utf8-fix-{build,profile-results,test_dm_names,negative-build,negative}.log,
/tmp/dm-utf8-fix-{original-build,original,original-validation,json-validation}.log,
/tmp/dm-utf8-fix-{sanitizers-build,sanitizers-results,sanitizers-test_dm*,full-check,netns}.log.
Задача UTF-8 закрыта;общий аудит DM остаётся частичным:crypto[V],остальные6headers
и dm_arch[~]. Платформенные GUI/Android/Windows/FreeBSD проверки не выполнялись.
Финальная сверка перед отправкой:fetch принёс4 Android mute-коммита до fa76447f.
Rebase прошёл без конфликтов;DM исходники/headers,Makefile и регрессия побайтно
сохранены. Коммиты исправления/отчёта после rebase:d09ed031/87d24b72.
Повторная native сборка PASS;check.sh205/205 PASS,0 failed/0 skipped,proxy9/9,
burst1/1,load8/8 PASS,134217728байт,exit0,175с. Строгие273 JSON/9452строки снова PASS.
Логи:/tmp/dm-utf8-fix-rebase-{build,full-check,json-validation,netns}.log.
Санитайзеры после rebase не повторялись:DM runtime не менялся,общий call_audio.h
в upstream изменяет только комментарий;новые платформенные Android callers этим
DM-профилем не проверяются. Upstream задачи/отчёты Android mute сохранены целиком.