Как фрагмент CSS разметки сломал C++ компилятор

    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
    PVS-Studio
    243,00
    Static Code Analysis for C, C++, C# and Java
    Поделиться публикацией

    Комментарии 14

      0
      А такая многострочная строка — это стандартная штука или фишка студии?
        +3
          0
          Из любопытства загуглил — оказывается и в VB с 14 версии завезли multiline string literals. И что примечательно, достаточно давно — а я и не знал, хотя фишка полезная(как и ряд других описанных по ссылке). И в шарпе есть что-то подобное — verbatim identifier(не знаю когда появилось, может и всегда было :)). Хорошо когда возможности языков сближаются, и при выборе языка можно брать тот что больше нравится :).
        +3
        Чет я не помню, чем же обсуждение закончилось когда мультилайны добавляли — упоминали же про #препроцессинг в них. Забили?

        Кстати, из прошлой статьи я узнал что вы еще и HTML в сконструированных строках проверяете. Это уже ваще отвал башки :)
          +3
          Вопрос не понял. Возможно, я не участвовал в том обсуждении. Напомните?
          Кстати, из прошлой статьи я узнал что вы еще и HTML в сконструированных строках проверяете. Это уже ваще отвал башки :)
          Некоторые о PVS-Studio до сих пор впервые узнают на том же хабре)
            +1
            Я имею ввиду, что-то на open-std.org — был же пропозал по которому добавили мультилайновые литералы? Не могли же не обсуждать #xxx в нём.
          –4

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

            +1
            А причем тут С/С++? Вы статью читали?
            0
            А там кавычки внутри, нет?
              0
              И что? Не )<<<" и ладно.
              0
              A fix for this issue has been released in VS 2019 16.0 Preview 4 and VS 2019 16.0 RC.
                0
                Не хватает экранирования кавычек во втором ряду строкового литерала.
                Странно, что вообще компилируется (проверять я конечно же не буду), но строки лучше писать так:
                std::string str = «some text»
                «second row»
                «third row»

                «last row»;
                  0
                  Оно не нужно для R литерала. Компилируется так как по стандарту
                    0
                    Спасибо за ссылку.

                    Препроцессинг мог остаться старый, в то время как компиляцию мелкомягкие сделали нормально.

                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                Самое читаемое