Category Archives: С/C++

Баг Konsole повержен !

Written by elwood

Вчера ночью я наконец добил этот баг, а сегодня вечером патч уже был закоммичен в master git-репозитория konsole. Для того, чтобы разобраться в сути проблемы, понадобилось несколько вечеров, пара виртуалок с линуксами OpenSuse (здесь, собственно, баг был обнаружен) и Debian (на ней я работал с KDevelop, потому что мне показалось, что gdb будет работать лучше в стабильной версии KDevelop – на самом деле всё было так же как и в OpenSuse) и исходники konsole и xterm.

Поиск точки сбоя

Как известно, чтобы поправить что-то, нужно сначала разобраться, что именно работает не так, локализовать проблему. Предстояло определить, что служит причиной неверного вывода на экран. Исходники konsole написаны хорошо, с большим количеством комментариев и удачными названиями классов, поэтому кандидаты на пристальный осмотр были определены сразу: классы TerminalDisplay, Emulation, Vt102Emulation, Pty и Screen. Идея была следующая: написать дампер текущего состояния визуализации и вызывать его при каждом обновлении. Обновление производил TerminalDisplay в функции updateImage(), и я добавил в него дамп матрицы символов и атрибутов, которые должны быть выведены на экран. После испытаний выяснилось, что в этом месте ошибочные атрибуты последних символов уже сформированы, и, значит, надо искать проблему не в выводе на экран, а в коде, который формирует эту матрицу буфера вывода.

Если мы с вами посмотрим на то, что такое эмуляторы терминала, то увидим, что они работают следующим образом. На входе эти программы получают последовательность байт (в которых кодируются как символы для вывода, так и различные управляющие коды), внутри себя они интерпретируют её как последовательность команд вида “добавь символ X”, “установи курсор в (1;3)”, “поменяй текущий цвет на Green” и на выходе выдают ту самую матрицу символов и атрибутов, которая выводится на экран.

Чтобы быстро понять, какие команды генерирует тестовая программа на ncurses, я расставил брейкпоинты на большинство методов класса Screen. И после некоторых мучений обнаружил, что при ширине экрана > 80 ncurses генерирует не те команды, что приходят, когда ширина экрана меньше 80 ! Выяснилось, что ncurses внутри оптимизирует свой вывод, и в проблемном случае для строки возвращает последовательность управляющих кодов, которая делает только удаление одного символа! А в конец строки после этого уже ничего не дописывается, и там появляется пустота.

Исцеление

Встал вопрос – почему эта штука работает в других эмуляторах терминалов ? За ответом было решено лезть в исходники gnome-terminal (точнее, vte – библиотеки, которую gnome-terminal использует для эмуляции), но они оказались намного менее читаемы по сравнению с konsole. И я попробовал вместо гномовских посмотреть исходники xterm, благо они оказались более понятны. И нашёл код функции удаления символа, из которого стало понятно, что после удаления символов будут дописаны пробелы справа, но не с пустыми атрибутами, а с теми, которые установлены сейчас в консоли.

Собственно, после этого уже не составляло труда дописать пару строк, исправляющих проблему. Протестировал на тестовом приложении, запустил и console framework, проверил работоспособность нескольких других консольных программ (mc, vim), всё было ок, оставалось предложить патч для исправления бага. Для этого оказалось достаточным написать комментарий с детальным описанием сути проблемы и приложить патч. В течение следующего дня патч был проверен и закоммичен в master.

Успех.jpg:

На этом подвожу итог с разборками в Konsole, рад как слон, что не придётся писать обходные пути в console framework для рендеринга в konsole-based эмуляторах терминала. Интересно, сколько времени пройдёт до тех пор, пока фикс не будет втянут в пакеты популярных дистрибутивов ? Прямо реально интересно, готов даже не лениться и периодически проверять самые ходовые дистрибутивы (Fedora, CentOS, OpenSuse, Debian, Ubuntu, Arch, Gentoo). Только не знаю, как.

Впечатления от KDevelop

Written by elwood

KDevelop-logo

Ковыряясь с багом в Konsole, попробовал “родную” IDE для программирования под KDE – KDevelop. Мне нужно было чтобы IDE умела:

  • Импортировать проект из cmake-файла
  • Редактировать C++ код с более или менее удобной навигацией
  • Собирать проект, желательно одной кнопкой
  • Запускать проект в отладчике, желательно одной кнопкой

Сначала думал попробовать Eclipse, так как нашел в сети инфу о каком-то плагине, который по cmake-файлу умеет генерировать eclipse project, но в jabber конфочке мне подсказали, что KDevelop умеет это делать из коробки.

В общем, с первым пунктом KDevelop вполне справился. Единственное замечание: импорт не работает, если вы выбираете папку с проектом, к которой у KDevelop нет доступа. Я скачал исходники из-под рута, а KDevelop был запущен под обычным пользователем. Проблема заключается в том, что KDevelop не сообщает о сути ошибки, а просто молча ничего не делает. Возможно, эта проблема уже исправлена в более свежих версиях (я работал с KDevelop в Debian, в который как известно, попадают не самые свежие версии пакетов). Работает также импорт из обычных make-файлов (которые появляются после выполнения ./configure). Так я сымпортировал туда же проект xterm (то есть для обычного make сначала нужно выполнить ./configure, а потом импортировать проект в KDevelop).

KDevelop-overview

Второй пункт тоже отработал замечательно – навигация по С++ действительно хороша, IDE умеет переходить не только по Ctrl+Click к объявлению функции, но и по клику на сигнатуру объявления функции – к её определению. Также хорошо показываются комментарии к функциям. Есть навигация вперёд-назад по Cmd+Right/Left. Тела макросов показываются при наведении мышкой. Неприятный момент: если отсутствуют нужные библиотеки, их инклуды подсвечиваются красным, и после установки требуемых заголовочных файлов это уже не исправляется, пришлось перезапускать IDE. Впрочем, это мелочь.

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

KDevelop-Launches-1

А можно выбрать просто путь к исполняемому файлу, который появится в результате сборки:

KDevelop-Launches-2

Для отладчика мне хватило прописать “gdb”:

KDevelop-Launches-3

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

Кнопка Build selection вроде бы должна собирать только тот проект, который у меня сейчас под курсором мыши, но почему-то собираются все проекты. Непонятно, но фиг с ним, думается, что в противном случае было бы больше проблем.

Debug запускает выбранный Launch под отладчиком. С Konsole такое почему-то не заработало, но можно было сначала нажать Execute, а потом приаттачиться к процессу. Отладчик вполне работоспособен, хотя трассировка хромает не по-детски. Лучше ставить брейкпоинты. Несколько раз вылетало в одном и том же месте (gdb слетал, программа продолжала работать) – при наведении мыши на локальную переменную, которая должна содержать строку в unicode. Потом вроде починилось, но осадок остался. Видимо, отладка ещё довольно сырая, и уповать на неё не стоит.

В целом, впечатление хорошее. Раньше я для написания мелких тестовых программ на Си пользовался CodeBlocks, теперь, наверное, буду использовать KDevelop. В первую очередь, из-за хорошей поддержки make и cmake и удобной навигации по коду.

Лёд тронулся!

Written by elwood

Недавно я наткнулся на проблему с рендерингом console framework в стандартном эмуляторе терминала для KDE – Konsole. Проблема заключалась в том, что при перемещении окошек влево в терминале с шириной, равной или меньше ширины буфера экрана, справа от окна появлялись артефакты:

До этого я тестировал в других эмуляторах терминала (gnome-terminal, xterm, putty), и таких проблем не возникало никогда. После некоторых исследований стало ясно, что это бага в самом Konsole. Я был очень удивлён и не питал особых надежд на то, что такой баг можно легко воспроизвести, а тем более убедить мейнтейнеров проекта. Во всяком случае прикладывать к багрепорту аттач с программой на моно, которая внутри неочевидно (для мейнтейнеров) работает, имело бы мало смысла. Поэтому я решил попробовать сделать тестовую программу на чистом Си, минимального размера, но чтобы проблема была наглядно продемонстрирована. И это получилось ! Текст программы можно посмотреть в описании бага. Демонстрация проблемы была наглядна:

После этого я попросил в конференции гентоводов проверить, воспроизводится ли проблема у них. Пользователи Gentoo устанавливают одни из самых последних билдов программ, поэтому проверка у них – это важно. Оказалось, что баг действительно воспроизводится. Прошла неделя, я потихоньку уже сам стал разбираться в исходниках Konsole, научился собирать из исходников, логировать данные в момент обновления экрана, и вот сегодня – баг получил статус CONFIRMED, а значит, и некоторый шанс на то, что им кроме меня кто-то займётся.