вторник, 1 января 2030 г.

О блоге

Более тридцати лет я занимался разработкой ПО, в основном как программист и тим-лид, а в 2012-2014гг как руководитель департамента разработки и внедрения ПО в компании Интервэйл (подробнее на LinkedIn). В настоящее время занимаюсь развитием компании по разработке ПО stiffstream, в которой являюсь одним из соучредителей. Поэтому в моем блоге много заметок о работе, в частности о программировании и компьютерах, а так же об управлении.

Так же я пишу о жизни вообще и о нескольких своих увлечениях: о фотографии (включая публикацию своих фотографий, некоторые есть и на ZeissImages), о спорте, особенно о дартсе, и, совсем коротко, о кино.

понедельник, 31 декабря 2029 г.

[life.photo] Характерный портрет: вы и ваш мир моими глазами. Безвозмездно :)

Вы художник? Бармен или музыкант? Или, может быть, коллекционер? Плотник или столяр? Кузнец или слесарь? Владеете маленьким магазинчиком или управляете большим производством? Реставрируете старинные часы или просто починяете примус? Всю жизнь занимаетесь своим любимым делом и хотели бы иметь фото на память?

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

понедельник, 8 июня 2026 г.

[life.audiophilia.diy] Попробовал давеча 10mm динамики в наушниках-затычках. На свою голову...

Поскольку в области 15.4mm и 14.8mm динамиков для наушников-вкладышей перепробовал уже практически все, что заслуживало внимания, то решился на эксперимент с 10mm динамиками для внутриканальных наушников. Но т.к. заушные мониторы мне не подходят, то остановился на форм-факторе "затычек".

Взял вот эти недорогие (по меркам 10mm динамиков) драйверы:

И установил их вот в такие корпуса (из черного дерева):

Немного помучался с подбором амбушюр...

Но результат получил такой, что даже и не знаю как охарактеризовать.

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

Но даже если не брать особенности НЧ, то и на всех остальных диапазонах сплошные кардинальные улучшения. Все гораздо более отчетливее. Плюс гораздо большая "глубина" сцены.

В общем, в затычках как будто бы выходишь на совершенно другой уровень.

Однако, есть подозрение, что все это далеко не бесплатно для ушей. Чтобы все эти прелести воспринимать мне нужны амбушюры размера L. И хоть я и выбрал самые мягкие из имеющихся, но все равно ощущение, что вставляешь толстые палки в слуховые каналы. Это ощущение практически исчезает минут через 7-10 после начала прослушивания, хотя того комфорта, который есть со вкладышами, когда "вставил и забыл", нет и близко. Поэтому когда наушники извлекаешь, то чувствуешь пусть и небольшое, но физическое облегчение. А такой дискомфорт, хоть он и не сильный, вряд ли полезен для слуха.

Так что очень стремно своими новыми затычками пользоваться. Как бы потом не пришлось расплачиваться за хороший звук проблемами с перепонками из-за усиленного образования ушной серы.

понедельник, 1 июня 2026 г.

[prog.c++] Попробовал познакомиться с модулями C++20 и чего-то недопонял

Провел пару простых экспериментов с модулями C++20 и получил странные результаты.

Эксперименты проводились под Windows с VS2022 и VS2026 (обновления от мая 2026-го) и ArchLinux с GCC 16.1 и clang 22.1.

Ожидаемые мной результаты (т.е. отсутствие проблем компиляции/линковки) получились только с clang 22.1 и libc++. А вот с GCC и VC++ случились какие-то проблемы, которые мне сложно объяснить.

Во всех случаях сборка осуществлялась через CMake и Ninja.

Исходные коды описанных ниже тестовых программ можно найти в этом репозитории.


Эксперимент первый (case_001 из упомянутого репозитория). Очень простой модуль. Декларация в файле hello.ixx:

[life.cinema] Очередной кинообзор (2026/05)

Традиционный отчет о промостренных фильмах. Традиционно в начале каждого из списков идет то, что понравилось больше, а в конце то, на что можно и не тратить свое время.

Фильмы

Полный Такос (Operation Taco Gary's, 2026). Совершенно укуренный и классный фильм. Мне зашел, но из-за его специфичности рекомендовать не могу -- наверняка понравится не всем. Однако, хороший пример того как за дешево можно снять приличную юмористическую фантастику.

Эдем (Eden, 2024). Хорошая история, хорошая операторская работа, отличная игра актеров. Но вот рассказана эта история так, что не особо и цепляет. Поэтому самые сильные впечатления производят реальные фотографии и кадры хроники, показанные в самом-самом конце.

Они убьют тебя (They Will Kill You, 2026). Неплохая черная комедия в стиле фэнтези с реками крови и грудами отрубленных конечностей.

Взлом на миллион (Wardriver, 2026). Не ждал от фильма ничего хорошего, но был приятно удивлен. Далеко не шедевр, но вполне себе добротный криминальный фильм с неплохими сюжетными ходами.

Нормал (Normal, 2025). Не понял что это было: для комедии вроде бы слишком нудный, для боевика слишком комедийный. Посмотреть можно, но лучше ничего особенного не ждать.

Сезон охоты ("Blood of Man" или "Hunting Season", или "Mermaid", 2025). Добротно, но слишком уж неторопливо и маловато экшОна. По сути, весь фильм держится на харизме Мэла Гибсона.

Мумия ("The Mummy" или "Lee Cronin's The Mummy", 2026). Для своего жанра, в принципе, нормально. Но манера съемки у фильма такая, что воспринимается это все как театральная постановка и поэтому погружения в атмосферу ужаса не происходит.

Охота ("Hunt" или "Heon-teu" или "헌트", 2022). Есть русский бунт, бессмысленный и беспощадный. А есть корейские боевики, не менее бессмысленные и беспощадные 🙂 А если для вас все корейцы на одно лицо и их имена вы не запоминаете вообще, то следить за логикой происходящего на экране будет совсем сложно.

Мститель (Protector, 2025). Что будет, если смешать "Рембо", "Заложницу" и "Джона Уика" в очень-очень бюджетном кино, да еще и с типа крутой теткой в главной роли? А вот унылое говно под названием "Мститель" и получится.

Пастбища богов (2025). Местами красивые пейзажи. Пожалуй, это единственное, что есть хорошего в данном "кино".

Сериалы

Пацаны (The Boys, пятый сезон, 2026). Самый слабый из все сезонов. Но если предыдущие понравились, то надо смотреть хотя бы для того, чтобы увидеть чем все закончилось.

Отпечатки (первый сезон, 2025). Пока смотришь -- интересно, да и главного злодея хорошо замаскировали до самой последней серии, за что авторам респект. Но вот когда начинаешь задаваться вопросами как же такое могло происходить, то возникает устойчивое ощущение, что нам втирали какую-то дичь. Так что по итогу остались негативные впечатления.

Гнев (Man on Fire, первый сезон, 2026). Первые серии бодренькие, затем какие-то тягомотные сопли, а в финале какой-то сплошной маразм. Так что можно смело пройти мимо.

вторник, 26 мая 2026 г.

[prog.c++.bugs] Похоже наткнулся на баг в GCC 12/13 под Linux-ом. Или нет.

Дело было так: есть некий объемный и сложный шаблон класса-контейнера. Для тестирования было создано приложение с юнит-тестами на базе Google.Test. В состав этого приложения входит порядка 30 (тридцати) .cpp-файлов. В некоторых из них происходит следующее:

namespace
{

template<typename T>
struct test_traits : public my_container::default_traits<T> {
  static constexpr std::size_t key_size = 3;
};

/* namespace anonymous */

TEST(my_container, some_test)
{
  my_container::my_map<int, test_traits> map;
  ... // какие-то действия с map.
}

Т.е. суть в том, что в десятке .cpp-файлов есть анонимные пространства имен, в каждом из которых определяется шаблон класса с именем test_traits. Затем этот шаблон используется для инстанцирования класса-контейнера.

Все это работало до тех пор, пока не был добавлен еще один .cpp-файл, в котором было практически тоже самое:

namespace
{

template<typename T>
struct test_traits : public my_container::default_traits<T> {
  static constexpr std::size_t key_size = 3;
  static constexpr my_container::mode use_mode =
      my_container::mode::versioned;
};

/* namespace anonymous */

TEST(my_container, some_test_versioned)
{
  my_container::my_map<int, test_traits> map;
  ... // какие-то действия с map.
}

И вот тут-то в some_test_versioned с map стали происходит странные вещи: возникали segmentation faults там, где их быть не должно было. Попытки отладить код приводили к тому, что отладчик показывал, что отрабатывают не те ветки if-ов. А отладочные печати содержали совсем не те значения, которые должны были бы быть.

Было полное ощущение, что GCC сошел с ума.

Проект, в рамках которого все это делается, собирается VC++ под Windows и GCC под Linux-ом. Под Linux-ами используются GCC 12 и 13. Конкретно я работаю с GCC 13, но проверил и под GCC 12. Сам проект уже не очень маленький, плюс подтягивает кучу зависимостей разного калибра (включая Folly и Abseil). Все это к тому, что мероприятие по перекомпиляции проекта под какой-то свежий GCC или clang -- это попытка с негарантированным результатом. Может повезти, а может и нет.

Под Windows проверил, там ничего подобного нет, все работает как и положено. А вот под Linux-овым GCC -- проблемы.

В итоге подумал о том, что GCC воспринимает все мои test_traits как нарушение ODR и я наступаю на грабли UB. Поэтому переименовал test_traits так, чтобы во всех .cpp-файлах имена оказались уникальными, даже не смотря на то, что живут они в анонимных пространствах имен.

После этого все описанные выше магические проблемы разом исчезли.

Есть у меня сильное подозрение, что это таки был баг в GCC. Поскольку, если мне не изменяет склероз, все, что определяется внутри анонимного пространство имен, должно быть абсолютно уникальным. В том числе это касается и шаблонов.

Но на 100% не уверен. Может быть здесь дело еще и в том, что у my_container::map есть шаблонный параметр шаблона, т.е.:

namespace my_container
{

template<typename T, template<typenameclass Traits>
class map { ... };

/* namespace my_container */

Поэтому его параметризация в тесте идет не конкретными типами, а шаблоном:

TEST(my_container, some_test_versioned)
{
  my_container::my_map<
    int// Это конкретный тип.
    test_traits // А это шаблон, который развернется в конкретный
                // тип уже внутри map.
  > map;
  ... // какие-то действия с map.
}

И вот именно из-за этого ODR и нарушается. Но это не точно. И я даже не знаю в какую часть C++ного стандарта заглядывать, чтобы выяснить кто именно был не прав.

четверг, 21 мая 2026 г.

[prog.c++] Обнаружился баг в timertt возрастом более 10 лет

Пользователи обнаружили в SObjectizer проблему, которая была вызвана неправильной работой механизма timer_heap в библиотеке timertt.

Эта библиотека написана мной осенью 2014-го года для того, чтобы можно было окончательно отвязать SObjectizer от ACE. И как раз тогда, чуть ли не в самой первой версии, допущена ошибка в операции удаления таймерной заявки в механизме timer_heap. Этот timer_heap реализован в виде binary heap на базе вектора. И как раз удаление из вектора и содержало проблему.

То, что я допустил достаточно дурацкую ошибку совсем не удивительно. Я вообще умудряюсь делать на удивление много ошибок при реализации простых структур данных (скажем, если приходится вручную программировать интрузивный двусвязный список, то я там обязательно в паре мест накосячу). Дополнительным отягчающим фактором стало то, что специфическое для timer_heap тестирование было проведено "по верхам". Думаю, что если бы в 2014-ом не поленился составить тест на базе примитивного fuzzing-а, то эта проблема вскрылась бы уже тогда. Но невнимательность + разгильдяйство сделали свое темное дело.

Более удивительно то, что этот баг проявился в полный рост только сейчас, в 2026-ом. Вот это внушаить 🤔

Какие выводы можно сделать?

  • вложения в качественное тестирование окупаются. Недостаточное тестирование обязательно проявится. В не самый подходящий момент;
  • существующие косяки обязательно повылазят как только библиотекой начнут пользоваться;
  • в чем можно быть точно уверенным, так это в том, что где-то в коде есть ошибка. И, скорее всего, не одна.

PS. Что меня еще очень сильно удивило, так это то, что люди смогли найти проблемное место в не самом тривиальном (даже для меня) коде. И, к тому же, предложили патч на базе которого я в итоге и сделал исправление. Значит пишу не такой уж и страшный код, если в нем можно разобраться.

PPS. Видимо, нужно найти время и вытащить timertt из старого svn-репозитория на SourceForge чтобы он продолжил жить на GitHub-е. Плюс выбросить оттуда MxxRu и перевести все на CMake (собственно, необходимость бодаться с CMake и является основным стоп-фактором). Нужно как-то себя заставить сделать это. Жаль только, что история коммитов при переносе в git потеряется 🙁

PPPS. Обновление для SObjectizer-а уже опубликовано в виде версии 5.8.5.1.