(no subject)
Nov. 27th, 2008 11:47 pmНедавно встретился со злобным багом в SWIG'е. Он падал и сообщал о синтаксических ошибках в одном из заголовочных файлов gtk+ в несуществующих строках.
Путем небольших экспериментов было выяснено, что такое поведение вызывает структура _GtkArg, которая содержит анонимные структуры с тремя уровнями вложенности:
struct _GtkArg { //.... union { /* flat values */ //.... /* structured values */ struct { GCallback f; gpointer d; } signal_data; } d; };
В документации что-то было сказано про ограниченную поддержку вложенных структур. Но то, что они будут вызывать ошибки парсинга, я не ожидал.
Попытки воспроизвести такое поведение на более мелких структурах не удавались.
Тогда попытался удалять из этой структуры ее элементы по одному. Поведение так и оставалось загадочным. Все стало более или менее проясняться, когда я добрался до комментариев. Если убрать комментарии, то все проходило нормально. Если комментарии оставить — были ошибки.
Тогда стал удалять по одному символу из комментариев и смотреть, что получается. «structured values», …, «structured» — все одно и то же, swig говорит о несуществующих синтаксических ошибках. Наконец, когда комментарий сократился до «struc», ошибки появляться перестали.
Мистика — говорят в таких случаях. Ведь комментарии должен убирать еще препроцессор.
Но слово «struct» показалось подозрительным. Гипотеза подтвердилась: если ставить на это место любой комментарий, в котором присутствует «struct», то выдаются ошибки. Если такой комментарий ставить куда-нибудь в другое место, ошибок нет.
Дальнейшие эксперименты показали, что аналогичное поведение наблюдается и со словами «class» и «union». Значит, что-то не так с лексическим анализатором — первое и очевидное, что пришло в голову. Вношу изменения в лексический анализатор swig'а, чтобы он выдавал последовательности лексем, которые он видит. Без комментария все лексемы в порядке, с комментарием — последовательность нарушается. Как будто часть текста после комментария просто становится не видна лексическому анализатору. Еще и то, что сообщения об ошибках содержали случайный мусор, привели к мнению, что где-то некорректно перезаписывается память.
Дальнейшая отладка привела к продукции для структур в грамматике парсера. Перед ней стоял интересный комментарий. Для интереса привожу его полностью.
/* ---------------------------------------------------------------------- Nested structure. This is a sick "hack". If we encounter a nested structure, we're going to grab the text of its definition and feed it back into the scanner. In the meantime, we need to grab variable declaration information and generate the associated wrapper code later. Yikes! This really only works in a limited sense. Since we use the code attached to the nested class to generate both C/C++ code, it can't have any SWIG directives in it. It also needs to be parsable by SWIG or this whole thing is going to puke. ---------------------------------------------------------------------- */
Такой комментарий не может не зацепить глаз.
Короткая трассировка приводит к функции dump_nested, которая натравливает парсер на чуть измененную строку у с объявлением структуры. Тут-то и стало ясно, откуда могут браться синтаксические ошибки. Следующая зацепка — «nasty hack alert» в комментарии.
В том, что передо мной «a sick hack», я убедился, увидев использование функции strstr для модификации фрагментов кода, с помощью которой производилась некоторая замена строк в коде. И в результате комментарий оставался без закрывающей его последовательности символов, и лексический анализатор не мог найти конца комментария, захватывая весь остаток файла в один большой комментарий.
Отыскание причины заняло два дня. Исправление (тоже в виде хака, который просто удаляет все комментарии из изменяемого кода) заняло 10 минут.
Патч отправляется разработчикам.
Непонятным остается то, почему в swig'е использован такой грубый метод.