¿Por qué se permite la ejecución de código Java en los comentarios con ciertos caracteres Unicode

java unicode comments


El siguiente código produce la salida "¡Hola Mundo!" (no realmente,inténtalo).

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

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

La razón de esto es que el compilador de Java analiza el carácter Unicode \u000d como una nueva línea y se transforma en:

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

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

De este modo,el resultado es un comentario que se "ejecuta".

Dado que esto puede usarse para "ocultar" código malicioso o lo que sea que un programador malvado pueda concebir, ¿por qué está permitido en los comentarios ?

¿Por qué lo permite la especificación de Java?




Answer 1 aioobe


La decodificación del Unicode tiene lugar antes que cualquier otra traducción léxica.El beneficio clave de esto es que hace trivial ir y venir entre el ASCII y cualquier otra codificación.¡Ni siquiera necesitas averiguar dónde comienzan y terminan los comentarios!

Como se indicó en la Sección 3.3 de JLS, esto permite que cualquier herramienta basada en ASCII procese los archivos fuente:

[...] The Java programming language specifies a standard way of transforming a program written in Unicode into ASCII that changes a program into a form that can be processed by ASCII-based tools. [...]

Esto da una garantía fundamental para la independencia de la plataforma (independencia de los conjuntos de caracteres soportados),que siempre ha sido un objetivo clave para la plataforma de Java.

Poder escribir cualquier carácter Unicode en cualquier parte del archivo es una característica muy útil,y especialmente importante en los comentarios,cuando se documenta el código en idiomas no latinos.El hecho de que pueda interferir con la semántica de manera tan sutil es sólo un (desafortunado)efecto secundario.

Hay muchos problemas con este tema y Java Puzzlers de Joshua Bloch y Neal Gafter incluyeron la siguiente variante:

¿Es un programa Java legal? Si es así,¿qué es lo que imprime?

\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

(Este programa resulta ser un simple programa de "Hola Mundo".)

En la solución del rompecabezas,señalan lo siguiente:

Más en serio, este rompecabezas sirve para reforzar las lecciones de los tres anteriores: los escapes Unicode son esenciales cuando necesita insertar caracteres que no se pueden representar de otra manera en su programa. Evítelos en todos los demás casos.


Fuente: Java: ¿Ejecutar código en los comentarios?




Answer 2 Holger


Como esto aún no se ha abordado, aquí hay una explicación de por qué la traducción de los escapes de Unicode ocurre antes de cualquier otro procesamiento del código fuente:

La idea detrás de esto era que permite traducciones sin pérdida del código fuente de Java entre diferentes codificaciones de caracteres. Hoy en día, existe un amplio soporte de Unicode, y esto no parece un problema, pero en aquel entonces no era fácil para un desarrollador de un país occidental recibir algún código fuente de su colega asiático que contenía caracteres asiáticos, hacer algunos cambios ( incluyendo compilarlo y probarlo) y devolver el resultado, todo sin dañar algo.

Por lo tanto, el código fuente de Java se puede escribir en cualquier codificación y permite una amplia gama de caracteres dentro de identificadores, caracteres y literales de String y comentarios. Luego, para transferirlo sin pérdidas, todos los caracteres no admitidos por la codificación de destino son reemplazados por sus escapes Unicode.

Este es un proceso reversible y el punto interesante es que la traducción puede hacerse mediante una herramienta que no necesita saber nada sobre la sintaxis del código fuente de Java ya que la regla de traducción no depende de ella. Esto funciona ya que la traducción a sus caracteres Unicode reales dentro del compilador también ocurre independientemente de la sintaxis del código fuente de Java. Implica que puede realizar una cantidad arbitraria de pasos de traducción en ambas direcciones sin cambiar el significado del código fuente.

Esta es la razón de otra característica extraña que ni siquiera ha mencionado: la sintaxis \uuuuuuxxxx :

Cuando una herramienta de traducción está escapando caracteres y encuentra una secuencia que ya es una secuencia escapada, debe insertar una u adicional en la secuencia, convirtiendo \ucafe en \uucafe . El significado no cambia, pero cuando se convierte en la otra dirección, la herramienta solo debe eliminar una u y reemplazar solo las secuencias que contienen una u por sus caracteres Unicode. De esa manera, incluso los escapes de Unicode se conservan en su forma original al convertir de ida y vuelta. Supongo que nadie usó esa característica ...




Answer 3 Pepijn Schmitz


Voy a añadir de forma completamente ineficaz el punto,sólo porque no puedo evitarlo y aún no lo he visto hecho,de que la pregunta es inválida ya que contiene una premisa oculta que es errónea,a saber,¡que el código está en un comentario!

En el código fuente de Java \u000d es equivalente en todos los sentidos a un carácter ASCII CR.Es una línea que termina,simple y llanamente,donde sea que ocurra.El formato de la pregunta es engañoso,a lo que corresponde sintácticamente esa secuencia de caracteres:

public static void main(String... args) {
   // The comment below is no typo. 
   // 
 System.out.println("Hello World!");
}

IMHO la respuesta más correcta es por lo tanto:el código se ejecuta porque no está en un comentario;está en la siguiente línea."Ejecutar el código en los comentarios" no está permitido en Java,tal como se esperaría.

Gran parte de la confusión se debe al hecho de que los resaltadores de sintaxis y los IDE no son lo suficientemente sofisticados como para tener en cuenta esta situación. No procesan los escapes de Unicode en absoluto, o lo hacen después de analizar el código en lugar de antes, como lo hace javac .




Answer 4 zwol


El escape \u000d finaliza un comentario porque los escapes \u se convierten uniformemente a los caracteres Unicode correspondientes antes de que el programa sea tokenizado. También puede usar \u0057\u0057 lugar de // para comenzar un comentario.

Este es un error en su IDE, que debería resaltar la sintaxis de la línea para dejar en claro que \u000d finaliza el comentario.

Esto también es un error de diseño en el lenguaje. No se puede corregir ahora, porque eso rompería los programas que dependen de él. \u compilador debe convertir los escapes al carácter Unicode correspondiente solo en contextos donde eso "tiene sentido" (literales de cadena e identificadores, y probablemente en ningún otro lugar) o se les debería haber prohibido generar caracteres en el U + 0000– Rango 007F, o ambos. Cualquiera de esas semánticas habría evitado que el comentario fuera terminado por el escape \u000d , sin interferir con los casos en los que los escapes \u son útiles; tenga en cuenta que eso incluye el uso de \u escapa dentro de los comentarios como una manera de codificar los comentarios en un alfabeto no latino, debido a que el editor de texto puede adoptar una visión más amplia de donde \u escapes son significativas que el compilador hace. (Sin embargo, no conozco ningún editor o IDE que muestre \u escapes como los caracteres correspondientes en ningún contexto).

Hay un error de diseño similar en la familia C, 1 donde la barra diagonal inversa-nueva línea se procesa antes de que se determinen los límites de comentario, por ejemplo

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

Menciono esto para ilustrar que resulta fácil cometer este error de diseño en particular, y no darme cuenta de que es un error hasta que sea demasiado tarde para corregirlo, si estás acostumbrado a pensar en la tokenización y analizar la forma en que piensan los programadores del compilador. sobre tokenización y análisis. Básicamente, si ya ha definido su gramática formal y luego a alguien se le ocurre un caso especial sintáctico: trigrafos, barra invertida-nueva línea, codificación de caracteres Unicode arbitrarios en archivos fuente limitados a ASCII, lo que sea, que necesita ser encajado, es más fácil agregue un pase de transformación antes del tokenizador que redefinir el tokenizador para prestar atención a dónde tiene sentido usar ese caso especial.

1 Para los pedantes: soy consciente de que este aspecto de C fue 100% intencional, con la justificación, no estoy inventando esto, de que te permitiría forzar mecánicamente el código de ajuste forzado con líneas arbitrariamente largas en tarjetas perforadas. Todavía era una decisión de diseño incorrecta.




Answer 5 Jonathan Gibbons


Esta fue una elección de diseño intencional que se remonta al diseño original de Java.

A los que preguntan "¿quién quiere que Unicode se escape en los comentarios?",supongo que son gente cuya lengua materna usa el conjunto de caracteres latinos.En otras palabras,es inherente al diseño original de Java que la gente pueda usar caracteres arbitrarios de Unicode donde sea legal en un programa de Java,más típicamente en comentarios y cadenas.

Podría decirse que es una deficiencia de los programas (como los IDEs)utilizados para ver el texto fuente que tales programas no pueden interpretar los escapes de Unicode y mostrar el glifo correspondiente.