скачать - проверить актуальность java




Почему разрешено выполнение кода Java в комментариях с определенными символами Unicode? (6)

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

Как указано в разделе 3.3 JLS, это позволяет любому инструменту на основе ASCII обрабатывать исходные файлы:

[...] Язык программирования Java определяет стандартный способ преобразования программы, написанной на Unicode, в ASCII, которая превращает программу в форму, которая может обрабатываться инструментами на основе ASCII. [...]

Это дает фундаментальную гарантию независимости платформы (независимости поддерживаемых наборов символов), которая всегда была ключевой целью для платформы Java.

Возможность написать любой символ Unicode в любом месте файла - это удобная функция, особенно важная в комментариях при документировании кода на нелатинских языках. Тот факт, что он может вмешиваться в семантику такими тонкими способами, является лишь (неудачным) побочным эффектом.

Есть много ошибок на эту тему, и Java Puzzlers Джошуа Блоха и Нила Гафтера включили следующий вариант:

Это легальная программа на Java? Если так, что это печатает?

\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020\u0020
\u0063\u006c\u0061\u0073\u0073\u0020\u0055\u0067\u006c\u0079
\u007b\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0020\u0020
\u0020\u0020\u0020\u0020\u0073\u0074\u0061\u0074\u0069\u0063
\u0076\u006f\u0069\u0064\u0020\u006d\u0061\u0069\u006e\u0028
\u0053\u0074\u0072\u0069\u006e\u0067\u005b\u005d\u0020\u0020
\u0020\u0020\u0020\u0020\u0061\u0072\u0067\u0073\u0029\u007b
\u0053\u0079\u0073\u0074\u0065\u006d\u002e\u006f\u0075\u0074
\u002e\u0070\u0072\u0069\u006e\u0074\u006c\u006e\u0028\u0020
\u0022\u0048\u0065\u006c\u006c\u006f\u0020\u0077\u0022\u002b
\u0022\u006f\u0072\u006c\u0064\u0022\u0029\u003b\u007d\u007d

(Эта программа оказывается простой программой "Hello World".)

В решении головоломки, они указывают на следующее:

Если серьезно, то эта головоломка подкрепляет уроки предыдущих трех: экранирование Unicode необходимо, когда вам нужно вставить символы, которые не могут быть представлены каким-либо другим способом в вашей программе. Избегайте их во всех остальных случаях.

Источник: Java: Выполнение кода в комментариях ?!

Следующий код производит вывод "Hello World!" (нет, на самом деле, попробуйте).

public static void main(String... args) {

   // The comment below is not a typo.
   // \u000d System.out.println("Hello World!");
}

Причина в том, что компилятор Java анализирует символ Unicode \u000d как новую строку и преобразуется в:

public static void main(String... args) {

   // The comment below is not a typo.
   //
   System.out.println("Hello World!");
}

Таким образом, в результате комментарий «исполняется».

Поскольку это можно использовать для «сокрытия» вредоносного кода или всего, что может представить злой программист, почему это разрешено в комментариях ?

Почему это разрешено спецификацией Java?


Единственные люди, которые могут ответить, почему экранирование Unicode было реализовано так, как они были, - это люди, которые написали спецификацию.

Возможная причина этого заключается в том, что было желание разрешить весь BMP как возможные символы исходного кода Java. Это представляет проблему, хотя:

  • Вы хотите иметь возможность использовать любой персонаж BMP.
  • Вы хотите иметь возможность вводить любой характер BMP достаточно легко. Способ сделать это с помощью экранирования Unicode.
  • Вы хотите, чтобы лексическая спецификация была легкой для чтения и записи, а также достаточно простой для реализации.

Это невероятно сложно, когда в бой вступает Unicode: это создает целый набор новых правил лексера.

Самый простой выход состоит в том, чтобы выполнить лексирование в два этапа: сначала найдите и замените все экранированные символы Юникода символом, который он представляет, а затем проанализируйте полученный документ, как если бы экранированные символы Юникода не существовали.

Плюсом этого является то, что его легко указать, поэтому он упрощает спецификацию и легко реализуется.

Недостатком является, ну, ваш пример.


Поскольку это еще не решено, здесь поясняется, почему перевод экранирования Unicode происходит перед любой другой обработкой исходного кода:

Идея заключалась в том, что он позволяет переводить исходный код Java без потерь между различными кодировками символов. Сегодня широко распространена поддержка Unicode, и это не выглядит проблемой, но тогда разработчику из западной страны было нелегко получить исходный код от своего азиатского коллеги, содержащий азиатские символы, внести некоторые изменения ( включая компиляцию и тестирование) и отправку результата обратно, все без ущерба для чего-либо.

Таким образом, исходный код Java может быть написан в любой кодировке и позволяет использовать широкий диапазон символов в идентификаторах, символьных и String литералах и комментариях. Затем, чтобы передать его без потерь, все символы, не поддерживаемые целевой кодировкой, заменяются их экранированием Unicode.

Это обратимый процесс, и интересным моментом является то, что перевод может быть выполнен инструментом, который не должен ничего знать о синтаксисе исходного кода Java, поскольку правило перевода не зависит от него. Это работает, поскольку перевод их фактических символов Unicode внутри компилятора происходит независимо от синтаксиса исходного кода Java. Это означает, что вы можете выполнить произвольное количество шагов перевода в обоих направлениях, не меняя смысла исходного кода.

Это причина другой странной функции, о которой даже не упоминалось: синтаксис \uuuuuuxxxx :

Когда инструмент перевода экранирует символы и встречает последовательность, которая уже является экранированной последовательностью, он должен вставить дополнительный u в последовательность, преобразовав \ucafe в \uucafe . Смысл не меняется, но при преобразовании в другом направлении инструмент должен просто удалить один u и заменить только последовательности, содержащие один u на символы Unicode. Таким образом, даже экранированные символы Юникода сохраняются в своем первоначальном виде при конвертации назад и вперед. Я думаю, никто никогда не использовал эту функцию ...


Это был намеренный выбор дизайна, который восходит к первоначальному дизайну Java.

Тем людям, которые спрашивают «кто хочет, чтобы Unicode избегал комментариев в комментариях?», Я предполагаю, что это люди, чей родной язык использует латинский набор символов. Другими словами, в первоначальном дизайне Java заложено, что люди могут использовать произвольные символы Unicode везде, где это разрешено в программе Java, чаще всего в комментариях и строках.

Возможно, в программах (таких как IDE), используемых для просмотра исходного текста, есть недостаток, заключающийся в том, что такие программы не могут интерпретировать экранирование Unicode и отображать соответствующий глиф.


Я согласен с @zwol, что это ошибка дизайна; но я еще более критично отношусь к этому.

\u escape полезен в строковых и символьных литералах; и это единственное место, где оно должно существовать. Он должен обрабатываться так же, как и другие экранированные символы, такие как \n ; и "\u000A" должно означать точно "\n" .

Абсолютно \uxxxx иметь \uxxxx в комментариях - никто не может это прочитать.

Точно так же нет смысла использовать \uxxxx в другой части программы. Единственное исключение, вероятно, в общедоступных API, которые принудительно содержат некоторые не-ascii-символы - что в последний раз мы видели это?

У дизайнеров были свои причины в 1995 году, но спустя 20 лет это, кажется, неправильный выбор.

(вопрос к читателям - почему этот вопрос продолжает получать новые голоса? Этот вопрос связан где-то популярно?)


\u000d завершает комментарий, потому что экранирования \u равномерно преобразуются в соответствующие символы Unicode перед токенизацией программы. Вы можете в равной степени использовать \u0057\u0057 вместо // чтобы начать комментарий.

Это ошибка в вашей IDE, из-за которой синтаксис должен выделять строку, чтобы было ясно, что \u000d заканчивает комментарий.

Это также ошибка дизайна в языке. Это не может быть исправлено сейчас, потому что это сломало бы программы, которые зависят от него. \u escapes должны быть либо преобразованы компилятором в соответствующий символ Unicode только в тех контекстах, где это «имеет смысл» (строковые литералы и идентификаторы, и, вероятно, нигде больше), либо им должно быть запрещено генерировать символы в U + 0000– Диапазон 007F или оба. Любая из этих семантик предотвратила бы завершение комментария при помощи \u000d экранирования, не \u000d случаи, когда экранирование \u полезно - обратите внимание, что это включает использование экранирования \u внутри комментариев как способ кодирования комментариев в -Латинский скрипт, потому что текстовый редактор может иметь более широкое представление о том, где \u выходы значительнее, чем компилятор. (Я не знаю ни одного редактора или IDE, которые будут отображать экранированные символы \u как соответствующие символы в любом контексте.)

Существует аналогичная ошибка проектирования в семействе C, 1 когда обратная косая черта обрабатывается до определения границ комментариев, например,

// this is a comment \
   this is still in the comment!

Я привожу это, чтобы проиллюстрировать, что бывает легко совершить эту конкретную ошибку проектирования, и не понимаю, что это ошибка, пока не стало слишком поздно ее исправлять, если вы привыкли думать о токенизации и разбирать способ, которым думают программисты компилятора о токенизации и разборе. По сути, если вы уже определили свою формальную грамматику, а затем кто-то придумает особый синтаксический случай - триграфы, обратную косую черту, кодирование произвольных символов Unicode в исходных файлах, ограниченных ASCII, что угодно, - что нужно вставить в код, проще добавьте проход преобразования перед токенизатором, чем переопределить токенизатор, чтобы обратить внимание на то, где имеет смысл использовать этот особый случай.

1 Для педантов: я знаю, что этот аспект C был на 100% преднамеренным, с обоснованием - я не придумываю это - что это позволило бы вам механически втиснуть код произвольно длинными линиями в перфокарты. Это было все еще неправильное дизайнерское решение.





comments