Picture 1

В методологии статического анализа применяются разные технологии. Одна из них — препроцессирование файлов непосредственно перед их анализом. Препроцессированные файлы создаёт компилятор, запускаемый в специальном режиме работы. К сожалению, этот режим не очень хорошо тестируется, как показывает наш многолетний опыт разработки статического анализатора кода. В этой заметке приведу пример свеженайденного бага в С++ компиляторе от Microsoft.

Введение


Для демонстрации возможностей статического анализатора PVS-Studio наша команда проверяет исходный код Open Source проектов. Это существенный вклад в качество открытого программного обеспечения, дополнительная реклама и тестирование анализатора. Иногда мы выявляем очень необычные проблемы в компиляторах, с которыми сложно что-то сделать на стороне анализатора. Так, коллега недавно писал статью "Перестал анализироваться файл с директивой 'import' (compiler internal error 'msc1.cpp'). Что делать?", чтобы помочь нашим пользователям в решении «чужой» проблемы.

Причём тут CSS?


Не менее интересный баг был найден мной только что при проверке большого проекта. Компилятор Microsoft для C/C++ версии 19.16.27027.1 (Visual Studio v15.9.9) выдал такую ошибку при анализе нескольких файлов:

fatal error C1021: invalid preprocessor command 'tooltiphint'

Очевидно, это не директива препроцессора, но что же это? Это фрагмент CSS кода:

#tooltiphint {
  position: fixed;
  width: 50em;
  margin-left: -25em;
  left: 50%;
  padding: 10px;
  border: 1px solid #b0b0b0;
  border-radius: 2px;
  box-shadow: 1px 1px 7px black;
  background-color: #c0c0c0;
  z-index: 2;
}

После просмотра фрагмента стало понятно, что компилятор ошибается во время препроцессирования файла, но при этом код компилируется успешно. Фрагмент CSS кода является частью строкового литерала C++ кода. Вот так выглядит пример кода, достаточный для повторения ошибки:

std::string test = R"<<<(
<style type="text/css">
body { color:#000000; background-color:#ffffff }
body { font-family:Helvetica, sans-serif; font-size:10pt }

#tooltiphint {
  position: fixed;
  width: 50em;
  margin-left: -25em;
  left: 50%;
  padding: 10px;
  border: 1px solid #b0b0b0;
  border-radius: 2px;
  box-shadow: 1px 1px 7px black;
  background-color: #c0c0c0;
  z-index: 2;
}
.macro {
  color: darkmagenta;
  background-color:LemonChiffon;
  /* Macros are position: relative to provide base for expansions. */
  position: relative;
}

</style>
</head>
<body>)<<<";

Приведённый фрагмент кода не мешает успешной компиляции, но, в то же время, в режиме препроцессирования (флаг /P) возникнет ошибка.

Вот такая непростая жизнь у разработчиков статических анализаторов :). Вроде виноват не PVS-Studio, но всё равно мы должны заниматься с подобными проблемами. Впрочем, в этом нет чего-то нового. С некоторыми другими подобными случаями можно познакомиться в статье "PVS-Studio и враждебная среда обитания".

Заключение


Эта проблема будет отправлена в официальный баг-трекер, но оперативное решение проблемы вряд ли возможно. Например, проблема с директивой #import, выявленная нами несколько месяцев назад, о которой я писал вначале, будет исправлена только в следующем релизе Visual Studio. Т.к. релиз новой Visual Studio 2019 состоится уже через неделю, скорее всего, этот баг не успеют исправить к этой дате. Пользователям PVS-Studio рекомендуем также воспользоваться макросом PVS_STUDIO.



Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Svyatoslav Razmyslov. How the CSS markup fragment broke the C++ compiler

Комментарии (10)


  1. DrZlodberg
    27.03.2019 10:42

    А такая многострочная строка — это стандартная штука или фишка студии?


    1. Kyoki
      27.03.2019 10:45

      1. BDI
        27.03.2019 12:06

        Из любопытства загуглил — оказывается и в VB с 14 версии завезли multiline string literals. И что примечательно, достаточно давно — а я и не знал, хотя фишка полезная(как и ряд других описанных по ссылке). И в шарпе есть что-то подобное — verbatim identifier(не знаю когда появилось, может и всегда было :)). Хорошо когда возможности языков сближаются, и при выборе языка можно брать тот что больше нравится :).


  1. datacompboy
    27.03.2019 11:22

    Чет я не помню, чем же обсуждение закончилось когда мультилайны добавляли — упоминали же про #препроцессинг в них. Забили?

    Кстати, из прошлой статьи я узнал что вы еще и HTML в сконструированных строках проверяете. Это уже ваще отвал башки :)


    1. SvyatoslavMC Автор
      27.03.2019 11:29

      Вопрос не понял. Возможно, я не участвовал в том обсуждении. Напомните?

      Кстати, из прошлой статьи я узнал что вы еще и HTML в сконструированных строках проверяете. Это уже ваще отвал башки :)
      Некоторые о PVS-Studio до сих пор впервые узнают на том же хабре)


      1. datacompboy
        27.03.2019 21:18
        +1

        Я имею ввиду, что-то на open-std.org — был же пропозал по которому добавили мультилайновые литералы? Не могли же не обсуждать #xxx в нём.


  1. akurilov
    28.03.2019 08:07
    -3

    Одна из причин, почему не C/C++


    1. Kyoki
      28.03.2019 10:10
      +1

      А причем тут С/С++? Вы статью читали?


  1. diakin
    29.03.2019 05:02

    А там кавычки внутри, нет?


    1. Kyoki
      29.03.2019 10:36

      И что? Не )<<<" и ладно.