>
>
Ошибка с директивой #line в компиляторе…

Святослав Размыслов
Статей: 90

Ошибка с директивой #line в компиляторе Visual C++

Директива #line добавляется препроцессором и затем может быть использована для понимания, к какому файлу и строке относится тот или иной фрагмент кода в препроцессированном файле. Директива #line указывает инструментам, работающим с кодом, изменить внутренний хранимый номер строки и имя файла компилятора на заданный номер строки. Следующие строки уже будут отсчитывать относительно заданной позиции. Явное препроцессирование, в основном, используется для отладки или различными генераторами. В любом случае, ошибка в таком функционале может приводить к разным негативным последствиям. Одна из таких проблем возникла у пользователя PVS-Studio в Visual Studio 2019.

История и описание ошибки

Директива #line - это важная часть препроцессированных файлов, которые используются анализатором PVS-Studio для выдачи предупреждений на нужные строки кода пользователей. Тут и начинается история поиска ошибки.

Один из наших пользователей с большой кодовой базой начал перевод всего проекта с Platform Toolset версии v141 на v142 в Visual Studio 2019. После чего, в результатах анализа возник всплеск предупреждений V002 и выдача нескольких десятков других предупреждений не на те строки кода (ошибка на одну строку).

Диагностика V002 как раз детектирует такие ситуации (некорректная нумерация строк). Обычно это возникает из-за многострочных макросов или других директив препроцессора (например, #pragma). Проблема возникает не очень часто, но преимущественно на компиляторе от Microsoft. Такой всплеск проблем на одном проекте был неожиданным, т.к. наша система тестирования не показывала наличия такой серьёзной проблемы, и мы начали отлаживать анализатор на препроцессированном файле пользователя.

Через несколько часов отладки мы установили, что анализатор уже работает с некорректными данными о строках кода и смогли составить тестовый пример:

#define MACRO(a, b)              // line1
                                 // line2
int main(int argc, char* argv[]) // line3
{                                // line4
    MACRO("Some string",         // line5
        42);                     // line6
    return 0;                    // line7 <=
}

Препроцессированный файл получается такой:

#line 1 "D:\\_Tests\\TestApp\\Project2\\rnd_bs.cpp"


int main(int argc, char* argv[])
{
  ;
#line 8 "D:\\_Tests\\TestApp\\Project2\\rnd_bs.cpp"
  return 0;
}

Оператор return находится на 7-й строке в исходном файле, а препроцессор указывает на 8-ю строку. Эта ошибка в препроцессоре возникла, предположительно, из-за многострочного макроса.

Релиз исправленной версии

На момент написания статьи, проблема была актуальна для последних версий Visual Studio, вплоть до версии 16.4.3 (от 14 января 2020 года). Мы открыли Bug Report "Invalid #line directive after preprocessing (VS2019, v142)" и через 4 дня получили интересный ответ:

This issue has been identified as a duplicate of an earlier reported feedback linked here: https://developercommunity.visualstudio.com/content/problem/738407/preprocessor-generates-incorrect-line-information.html. If you reported or voted here, your vote has been applied to the original issue. Everyone else can add their vote directly at the above linked feedback. Voting helps increase the priority of the issue by consolidating customer impact under one feedback. Thank you!

Оказывается, об этой проблеме уже сообщили, причём 18 сентября 2019 года – почти полгода назад: "Preprocessor generates incorrect line information". Пользователь представил аналогичные примеры кода для воспроизведения ошибки. По словам автора, ошибка существует как минимум с Visual Studio 2019 16.2.

Неизвестно, совпадение это или нет, но через несколько дней нашей активности ошибке присвоили статус Fixed - Pending Release.

19 мая 2020 года вышла исправленная версия Visual Studio 2019 16.6.0. Рекомендуем всем пользователям PVS-Studio перейти на неё.