Протестировал


Гео и язык канала: Россия, Русский
Категория: Технологии


Рекламу и анонсы не размещаю.
Авторский канал о качественной разработке ПО (процессы, тестирование, формальная верификация и спецификация).
Контакт: @ligurio

Связанные каналы  |  Похожие каналы

Гео и язык канала
Россия, Русский
Категория
Технологии
Статистика
Фильтр публикаций




В Github UI появился автоматический дедупликатор тикетов, во время создания нового тикета, но ищет похожие по описанию. Впрочем работает пока так себе, в моём случае это был не дупликат.


CirrusCI всё:
Cirrus CI will shut down effective Monday, June 1, 2026.


Перейдут под крыло OpenAI.
В прощальном тексте основатель перечисляет инновации:
Over the last nine years, we were fortunate to innovate across continuous integration, build tools, and virtualization. In 2018, we introduced what we believe was the first SaaS CI/CD system to support Linux, Windows, and macOS while allowing teams to bring their own cloud. In 2022, we built Tart, which became the most popular virtualization solution for Apple Silicon, along with several other tools along the way.

но я их ценил в первую очередь за возможность использования FreeBSD в CI.

https://cirruslabs.org/


Интересная статья про использование сравнительного тестирования для приложений с состоянием - "Vive la Différence: Practical Diff Testing of Stateful Applications".

При обновлении stateful-приложений работающих с БД часто возникают трудноуловимые ошибки и традиционные методы (канареечные релизы, роллинг-обновления, cине-зелёное развёртывание) плохо эти ошибки выявляют из-за разделяемого состояния. Стандартные тесты (юнит- и интеграционные) не проверяют взаимодействие разных версий во время обновления.

В статье предлагается использование фреймворка для сравнительного тестирования двух версий приложения (v1​ - текущая, v2​ - новая) на идентичность поведения. Фреймворк работает поверх существующего Postgres без модификации кода СУБД, его работа разделяется на три этапа:

- Ветвление - создание лёгких, изолированных веток исходной базы данных без её физического копирования. Ветвление реализовано для PostgreSQL с помощью вспомогательных таблиц вставки, удаления и представлений с триггерами. Создание ветки занимает


Раньше ведь как было: изучаешь теорию языков программирования и формальные методы, формальные грамматики, лексический и синтаксический анализ, работу c AST (обход дерева, трансформация), атрибутные грамматики и синтезируемые/наследуемые атрибуты, изучаешь системы типов, семантику программ, чтобы понимать, что означает программа, изучаешь межпроцедурный анализ. Изучаешь алгоритмы статического анализа: анализ потоков данных и анализ потоков управления, абстрактную интерпретацию, ML для статического анализа, изучаешь реализации SOTA статических анализаторов с открытым исходным кодом (вроде ничего не забыл). И через несколько лет вы может быть разработаете статический анализатор, который будет находить проблемы в популярных проектах с высоким уровнем качества кода.

А cейчас вы можете сделать расширение для популярной LLM из инструкций для этой LLM и вуаля, 500+ дефектов в CPython и C-расширениях для него.

В 2013 году Coverity сделали автоматический анализа кода на предмет наличия проблем безопасности и ошибок в CPython 3.3.2:

Если для ранее проанализированных открытых проектов зафиксирован средний уровень дефектов в 0.69 ошибок на 1000 строк кода, то для кода Python уровень дефектов составил всего 0.005. Если учесть, что требования промышленных стандартов качества допускают наличие 1 ошибки на 1000 строк кода, то качество кода Python в 200 раз выше данных требований.

В процессе проведения исследования было проанализировано около 396 тысяч строк кода CPython 3.3.2. В итоге было выявлено 278 новых дефектов, из которых 181 уже исправлен разработчиками Python (в сумме, с 2006 года в Python выявлено 996 ошибок, исправлено - 860). При рассмотрении других проектов размером от 100 до 500 тысяч строк кода, средний показатель дефектов для открытых разработок составляет 0.60, а для проприетарных - 0.66.

то есть код CPython действительно хорошего качества, по крайней мере был в 2013.

Все это нисколько не умаляет тех результатов, которые получил DevDanzin. По большому счёту не так важно для самих проектов каким способом и с помощью чего был найден дефект.

https://lwn.net/SubscriberLink/1067234/e5312bed2037a102/


Sashiko мониторит список рассылки с патчами в ядро Linux (LKML) и запускает ревью этих патчей с помощью LLM (сейчас, как я понял, это Gemini). Результаты публикует в симпатичном WebUI.

https://sashiko.dev/


SDLC.pdf
500.4Кб
Если вы хотели погрузиться в тему SDLC, то вот вам знак свыше: в весеннем семестре в ВМК МГУ проходит спецкурс по РБПО.

Лабораторные работы будут доступны только студентам, лекции будут транслироваться в Jitsi по ссылке, прослушивание доступно всем желающим просто по ссылке, записи лекций (кроме первой) обещают выкладывать. Лекторы из ИСП РАН и индустрии.

3 марта Вводная лекция.
10 марта Неопределенное поведение и оптимизация кода.
17 марта Статический анализ.
24 марта Задачи практического применения статического анализатора исходного кода компилируемых языков.
31 марта Обзор методик и инструментов архитектурного анализа. Композиционный анализ ПО.
7 апреля Анализ поверхности атаки.
14 апреля Фаззинг-тестирование.
21 апреля Оценка соответствия процессов РБПО в организации. Сертификация процессов РБПО.




Поиск точек разладки (changepoint) это популярная задача в разных областях. Это канал про тестирование ПО, поэтому ограничимся поиском точек разладки при анализе результатов тестирования производительности. В отличие от функционального тестирования результаты тестов производительности нужно постоянно анализировать и выявлять причины отклонений результатов, в некоторых компаниях этим занимаются отдельные команды (Андрей Акиньшин работе такой команды целую книжку посвятил, рекомендую к прочтению). Но если выделенной команды нет, а тестировать производительность всё еще хочется, то можно использоваться математические методы для анализа результатов. Не буду рассказывать, что задача поиска точек разладки непростая, Андрей Акиньшин это уже сделал. Вместо этого расскажу как это сделали мы в Tarantool.

Мы настроили запуск бенчмарков на выделенной машине со специальными настройками, все результаты, полученные от бенчмарков отправляли в InfluxDB и в графане можно было посмотреть результаты запуска бенчмарков на разных ветках и коммитах. В какой-то момент поняли, что смотреть каждый день на результаты тестов скучно и неинтересно, было бы здорово сделать автоматический анализ. На тот момент я нашел два проекта, которые могли бы помочь с этим: ruptures и hunter. Оба проекта написаны на Python, только первый больше библиотека для поиска точек разладки, а второй это законченный инструмент, который изначально разрабатывался в Datastax для поиска точек разладки в результатах бенчмарков. Я выбрал второй проект, сейчас он переехал в инкубатор Apache и называется Otava. Otava позволяет анализировать данные из различных источников (CSV files, PostgreSQL, BigQuery), настраивать степень отклонения при превышении которой сообщать о регрессии и т.д. Мы интегрировали Otava в Tarantool CI и Otava сообщает обо всех существенных отклонениях в результатах. Пока анализ работает в неблокирующем режиме, но возможно когда со временем мы переведем его в блокирущий режим, чтобы не мержить код, который заведомо приносит регрессии в производительности.

Про Apache Otava есть две публикации "Hunter: Using Change Point Detection to Hunt for Performance Regressions" и "8 Years of Optimizing Apache Otava: How disconnected open source developers took an algorithm from 𝑛3 to constant time".


После анонса задачи про верификацию оптимизаций в LuaJIT в лаборатории Tarantool мне написал студент Физтеха Алексей и сказал, что хочет взять эту задачу в качестве дипломной работы и с сентября прошлого года мы продолжаем делать верификатор для LuaJIT. Много успели сделать и есть результаты, которыми можно поделиться.

Напомню основную идею - научиться моделировать семантику LuaJIT IR с помощью SMT-LIB, декларативного LISP-подобного языка для SMT-солверов, и тем самым получить возможность проверять эквивалентность программы, представленной в виде LuaJIT до и после оптимизаций. В отличие от сравнительного тестирования верификация с помощью SMT-решателя позволяет проверить корректность на всех допустимых входах, а не только на конкретных тестовых данных.

До Алексея над задачей работали двое студентов, с которыми у нас появились первые результаты - они реализовали трансляцию для части IR инструкций и мы научились воспроизводить с помощью верификатора для реальных бага в LuaJIT. Сразу после начала стажировки Алексей быстро включился в работу, ознакомился с существующим кодом проекта и первым делом исправил проблемы, найденные во время ревью. Потом мы добавили поддержку арифметических инструкций (это было проще всего, потому что в SMT-LIB есть теории с поддержкой операций над целыми числами и числами с плавающей точкой), поддержали работу с памятью и поддержали проверку эквивалентности выходов с трасс и снапшотов. Пока мы не реализовали даже половину IR инструкций, но к сожалению всё смоделировать скорее всего и не получится: для одних инструкций недостаточно информации в IR, другие сложно или невозможно реализовать в SMT-LIB. Но похоже, что часть поведения программы, представленной в IR, мы научились моделировать и теперь хочется доказать работоспособность инструмента. Мы взяли корпус от нашего фаззера по грамматике Lua и Алексей для каждой программы запустил верификатор. Во время такого прогона нашли недочеты в трансляторе и один баг в LuaJIT (баг исправлен). Следующим шагом мы планируем научиться воспроизводить все известные исправленные баги в LuaJIT, связанные с оптимизациями, для этого репродьюсеры для этих багов конвертировали в тесты для ljopt, теперь Алексей будет кропотливо для каждого репродьюсера изучать IR трасс и учиться воспроизводить эти проблемы с помощью SMT-солвера. Надо сказать, что разрабатывая инструмент такого рода нужно пытаться не только заниматься моделированием IR, но и проверять работоспособность инструмента, вот мы и пытаемся всё время усидеть на двух стульях, переключаясь то на моделирование IR, то проверку инструмента.


Обычно для оценки степени покрытия кода фаззинг-тестированием используют покрытие по строкам/функциями и редко по ветвлениям. Метрика покрытия MC/DC редко используется для оценка покрытия регресионными тестами вообще и фаззинга в частности, хотя она позволяет получить доказательство того, что логика надежно тестируется в коде. Я сделал патч, чтобы можно было для кода PUC Rio Lua и LuaJIT собирать MC/DC покрытие, мне было интересно узнать значения метрики для этих двух проектов при тестировании нашими фаззинг-тестами. Поддержка покрытия MC/DC уже есть и в GCC и в Clang (18+ и это не возраст, а версия), так как тесты по умолчанию собираются с libFuzzer, то я использовал реализацию из LLVM/Clang. Результаты такие:

Общее покрытие MC/DC для кода LuaJIT 23%, некоторые файлы покрыты лучше других, топ-3: lj_parse.c - 95%, lj_buf.c - 88%, lj_str.c/lj_tab.c/lib_aux.c - 75%. Кажется здесь есть над чем подумать - файл для сборщика мусора покрыт на 97% по строкам и только 49% по MC/DC или lj_record.c по строкам 80% и 20% по MC/DC. В этих компонентах логика похоже плохо покрыта.

Общее покрытие MC/DC для кода PUC Rio Lua 23%, топ-3 файлов с большим покрытием: lstring.c/lzio.c - 100%, lopcodes.c - 83%.

Оговорюсь, что приведенные цифры могут неточно отражать действительность по некоторым причинам: в OSS Fuzz покрытие кода Lua на уровне 92% по строкам на протяжении наверное трёх лет или больше, то есть мой корпус для PUC Rio Lua при измерении был не совсем актуальный, при сборке PUC Rio Lua и LuaJIT компилятор часто показывал сообщения "unsupported MC/DC boolean expression; contains an operation with a nested boolean expression", возможно это повлияло на точность измерений.

Интересно, что Ричард Хипп даже противопоставляет фаззинг и 100% покрытие по MC/DC:

Фаззинг-тестирование и 100% тестирование MC/DC находятся в противоречии друг с другом. Код, протестированный на 100% MC/DC, будет более уязвим к проблемам, выявляемым фаззингом, а код, хорошо работающий во время фаззинг-тестирования, будет иметь (значительно) меньший процент MC/DC, чем 100%. Потому что тестирование MC/DC препятствует созданию защитного кода с недоступными ветвями, но без защитного кода фаззер с большей вероятностью найдет путь, который вызовет проблемы. Хотя фаззинговое тестирование и 100% MC/DC-тестирование находятся в противоречии, они не полностью противоречат друг другу. Тот факт, что набор тестов SQLite тестирует на 100% MC/DC, означает, что когда фаззеры находят проблемы, эти проблемы можно быстро исправить с минимальным риском появления новых ошибок.


In this work, we address this issue by proposing an efficient white-box checker, Emme. Our key idea is to use information that is easily provided by database systems to efficiently check the isolation level of a given transaction history. We present version certificate recovery, a method of recovering the version order and each operation’s version from the database system under test. For efficiency, we also propose the concept of an expected serialization order, which obviates the need to define and recover a version certificate for many serializable concurrency control protocols. We have implemented version certificate recovery for three widely used database systems—PostgreSQL, CockroachDB, and TiDB. We demonstrate that Emme is 1.2–3.6× faster than Elle, a state-of-the-art checker. Using the expected serialization order, we obtain a further speedup of 34–430× compared to Emme when checking histories containing predicate operations. We show that our approach can identify invalid histories that cannot be detected by Elle and also show that it can find realistic bugs purposely introduced by an engineer.

https://www.doc.ic.ac.uk/~afd/papers/2024/EuroSys.pdf


Что ж, настала пора. Подпишитесь на случай, если Телеграму станет совсем плохо.


Инженер из Mozilla в треде рассказывает, что проблемы в CPU не редкость, не то, что раньше. Мало ли чего в интернетах пишут, но этот инженер разбирает креши от Firefox и заботливо собирает
в один тикет - https://bugzilla.mozilla.org/show_bug.cgi?id=1896406. За год их накопилось 31 штука.

Тред: https://bsd.network/web/@gabrielesvelto@mas.to/115939583283721936


Вот и новогодние подарки от авторов Software Foundations подоспели.

We have a new, 7th (sic!) volume of Software Foundations: Security Foundations
https://softwarefoundations.cis.upenn.edu/secf-current/index.html

Topics include noninterference, security type systems, secure multi-execution, cryptographic constant time, and speculative load hardening. And that's not even all, as the volume is still in progress, and some new chapters are upcoming.


Статистика по фаззингу Linux-ядра с помощью syzcaller: медиана выявления бага 51 день, 75-й перцентиль 291 день. С августа 2025 года syzcaller делает шаг влево: серии патчей в рассылке по некоторым подсистемам ядра подвергаются фокусному фаззингу ещё на этапе ревью. Найденные креши, которые воспроизводятся без патчей, не репортятся. Фаззингу подвергаются только функции, у которых поменялся объектный код, и файлы, которые затронули патчи. С августа по декабрь было найдено 105 крешей.

https://ci.syzbot.org/stats


В прошлый понедельник вышла новая публичная версия PUC Rio Lua и хотя мы не успели сообщить о проблеме до релиза всё равно хотелось разобраться с целочисленным переполнением. Для репорта проблемы нужен репродьюсер, а у меня никак не получалось воспроизвести проблему на локальной сборке. Я стал минимизировать репро в контейнере OSS Fuzz. Получил репро на Lua и С, но с ними локально всё равно не воспроизводится. Минимизирую набор флагов компилятора, все равно локально не воспроизводится. Начинаю с нуля пошагово воспроизводить в окружении контейнера и не воспроизводится. Потом замечаю, что если путь к Lua-скрипту покороче, то воспроизводится, а если путь указывает на скрипт в отдельной директории, то не воспроизводится. Чудеса какие-то!

+++ luaL_loadbuffer_proto_test.c 2025-12-23 14:27:19.277975264 +0000
@@ -5,7 +5,7 @@
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
- luaL_loadfilex(L, "/src/testdir/repro.lua");
+ luaL_loadfilex(L, "/src/testdir/lua/repro.lua");
lua_call(L, 0, 0);
lua_settop(L, 0);
lua_close(L);

Экспериментирую дальше, выясняю, что длина пути влияет на воспроизведение. Чтобы упростить воспроизведение использую локальную директорию и указываю только имя файла. happy_new_year_2026.lua как раз подходит по длине и с ним всегда воспроизводится, локально в том числе.

Репорт в рассылке, проблема подтверждена, исправление скоро будет.


Любите ли вы отладку так, как люблю её я?

Время от времени от непрерывного фаззинга появляются срабатывания, которые надо разбирать, многие из них вызваны настоящими багами, но не все. Обычно мы стараемся все срабатывания разобрать как можно скорее и отрепортить их разработчикам LuaJIT и PUC Rio Lua, но иногда бывают "тяжелые" случаи и такой разбор задерживается. В начале декабря было два срабатывания для PUC Rio Lua: утечка памяти и целочисленное переполнение. Обе проблемы не получилось разобрать сразу, а тем временем в PUC Rio Lua один за другим выпускали RC для новой версии 5.5.0 и было желание как можно быстрее разобрать срабатывания. Чтобы разобрать каждое такое срабатывание надо научиться воспроизводить локально, без использования инфраструктуры OSS Fuzz, и потом минимизировать репро. По желанию можно сделать бисект по коммитам, чтобы понять когда проблема появилась.

Проблема с утечкой была странной. В PUC Rio Lua утечки памяти если и бывают, то очень редко, обычно все наши срабатывания в фаззинге заключались в нарушении инварианта в assert(). Ещё казался странным файл с входными данными, который воспроизводил проблему. Потому что он был похож на кашу из символов и токенов, похожих на ключевые слова Lua. Минимизировать такой файл было тяжело: creduce совсем не помог, а удаление любого символа ломало воспроизведение проблемы. У меня получилось только немного уменьшить репродьюсер, я не стал тянуть время, описал шаги по воспроизведению и отправил в рассылку. Один из пользователей посмотрел на репро и стал намекать, что входные данные похожи на бинарные, Lua интерпретирует их как байткод и если это так, то это ложноположительный репорт (FP). Я проверил загрузку входных данных с помощью другой функции из Lua C API, которая входные данные интерпретирует только как текст, и воспроизведение потерялось. Я отписал, что похоже это действительно FP. В ответ пишет Роберту Иерузалимски что это не FP и у него получилось воспроизвести проблему. Спустя день он минимизировал репро и превратил его в обычный скрипт на Lua:

collectgarbage'generational'


print(10, xpcall({}, function(msg)

print("1", load'A')
print(" 2", load'A.A')
print(" 3", load'A.A')
io.write(" 4 ", msg, "\n")

assert(string.gsub('....................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................', 'X', '') == '')

end))

А чуть позднее и описал причину:

I found the issue. Some calls to the finalizers that should free that
slot are failing due to (C) stack overflow. Because warnings were off (by
default), we do not see any message.

The leak is tricky because it only appears when a finalizer is called at
very specific points during the program. Any change in the rhythm of the
garbage collector affects it.

Probably the garbage collector should defer calling a finalizer when
there is no stack space to run it.


Исправление попало в версию 5.5.0.


Ребята из Kaspersky рассказали как сделали и используют робопалец для тестирования телефонов. Круто конечно, молодцы! А ведь начиналась такая автоматизация с более простой Тамары.


У автора рассылки The Pragmatic Engineer есть книга "The Software Engineer's Guidebook". Покрывает большой круг тем и конечно там есть глава про тестирование. Если вы читали другие книги по тестированию, то здесь вряд ли что-то новое узнаете. А вот история в начале главы занимательная. Помню, у нас в проекте сборка занимала несколько часов и разработчики не писали ни юнит-тесты ни модульные тесты вообще, продукт тестировали только целиком. И такое тестирование было очень болезненное. Не будь как Сэм, будь как Джесс.

Показано 20 последних публикаций.