programing

특정 Unicode 문자의 댓글에서 Java 코드를 실행할 수 있는 이유는 무엇입니까?

firstcheck 2022. 7. 24. 22:56
반응형

특정 Unicode 문자의 댓글에서 Java 코드를 실행할 수 있는 이유는 무엇입니까?

다음 코드는 "Hello World!"라는 출력을 생성합니다(아니, 실제로 사용해 보십시오).

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

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

그 이유는 자바 컴파일러가 유니코드 문자를 해석하기 때문입니다.\u000d새로운 라인으로 변환됩니다.

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

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

따라서 코멘트가 "실행"됩니다.

이것은 악성코드나 사악한 프로그래머가 상상할 수 있는 모든 것을 "숨기기" 위해 사용될 수 있기 때문에, 왜 댓글에 그것이 허용되는가?

Java 사양에서 이것이 허용되는 이유는 무엇입니까?

Unicode 디코딩은 다른 사전 변환보다 먼저 이루어집니다.이 방법의 주된 장점은 ASCII와 다른 부호화 사이를 오갈 수 없다는 것입니다.댓글의 시작과 끝을 알 필요도 없습니다!

JLS 섹션 3.3에서 설명한 바와 같이 ASCII 기반 툴은 다음과 같이 소스 파일을 처리할 수 있습니다.

[...] Java 프로그래밍 언어는 유니코드로 작성된 프로그램을 ASCII 기반 도구로 처리할 수 있는 형식으로 변경하는 표준 방법을 지정합니다. [...]

이는 Java 플랫폼의 주요 목표였던 플랫폼 독립성(지원되는 문자 집합의 독립성)에 대한 기본적인 보증을 제공합니다.

파일의 임의의 장소에 Unicode 문자를 쓸 수 있는 것은 깔끔한 기능이며, 라틴어 이외의 언어로 코드를 문서화할 때 특히 코멘트에서 중요합니다.그것이 그렇게 미묘한 방식으로 의미론을 방해할 수 있다는 사실은 단지 (불행한) 부작용일 뿐이다.

이 테마에는 많은 겟차스가 있으며 Joshua Bloch와 Neal Gafter의 Java Puzzler에는 다음과 같은 변종이 포함되어 있습니다.

이것은 합법적인 자바 프로그램입니까?그렇다면 무엇을 인쇄합니까?

\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" 프로그램으로 판명되었습니다.)

이 수수께끼의 해결 방법에서는, 다음과 같은 점을 지적하고 있습니다.

더 심각한 것은 이 퍼즐이 이전 세 가지 교훈을 보강하는 데 도움이 된다는 것입니다.유니코드 이스케이프는 다른 방법으로 표현할 수 없는 문자를 프로그램에 삽입해야 할 때 필수적입니다. 다른 경우에는 모두 피하십시오.


출처 : Java : 댓글로 코드 실행?!

이것은 아직 다루어지지 않았기 때문에, 여기에서는 Unicode의 변환이 왜 이스케이프 되는지에 대해 설명합니다.

다른 문자 인코딩 간에 Java 소스 코드의 무손실 번역을 가능하게 한다는 것이 그 배경의 아이디어였다.현재는 Unicode가 폭넓게 지원되고 있어 문제가 되지 않는 것처럼 보이지만, 그 당시에는 서양에서 온 개발자가 아시아 동료로부터 아시아 문자를 포함한 소스 코드를 받아 수정(컴파일 및 테스트 포함)한 후 결과를 반환하는 것이 쉽지 않았습니다.

따라서 자바 소스 코드는 임의의 인코딩으로 작성할 수 있으며 식별자, 문자, 문자 내에서 다양한 문자를 사용할 수 있습니다.String리터럴과 코멘트그런 다음 손실 없이 전송하기 위해 대상 인코딩에서 지원되지 않는 모든 문자가 Unicode 이스케이프로 대체됩니다.

이는 가역적인 프로세스로 변환규칙에 의존하지 않기 때문에 Java 소스 코드 구문에 대해 아무것도 알 필요가 없는 툴을 사용하여 변환을 수행할 수 있습니다.이는 컴파일러 내의 실제 Unicode 문자로의 변환이 Java 소스 코드 구문과 독립적으로 이루어지기 때문에 작동합니다.이는 소스 코드의 의미를 변경하지 않고 양방향으로 임의의 수의 변환 단계를 수행할 수 있음을 의미합니다.

이것은 언급조차 하지 않은 또 다른 이상한 기능의 이유입니다.\uuuuuuxxxx구문:

변환 툴이 문자를 이스케이프하고 있을 때 이미 이스케이프된 시퀀스를 발견하면 추가 명령어를 삽입해야 합니다.u시퀀스로 변환,\ucafe로.\uucafe의미는 변하지 않지만, 다른 방향으로 변환할 때는 1개만 삭제해야 합니다.u단일 파일을 포함하는 시퀀스만 바꿉니다.u유니코드 문자를 기준으로 합니다.이렇게 하면 Unicode 이스케이프도 앞뒤로 변환할 때 원래 형태로 유지됩니다.아무도 이 기능을 사용하지 않았을 겁니다.

이 질문에는 잘못된 전제가 포함되어 있기 때문에, 즉 코드에 코멘트가 포함되어 있기 때문에, 나는 스스로 할 수 없고, 아직 그것을 본 적이 없기 때문에, 전혀 요점을 덧붙일 필요가 없습니다.

Java 소스 코드 \u000d는 모든 면에서 ASCII CR 문자와 동일합니다.어디서든 그것은 간단하고 단순한 행의 결말이다.질문의 서식은 오해의 소지가 있습니다.문자의 시퀀스가 실제로 구문적으로 대응하고 있는 것은 다음과 같습니다.

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

따라서 IMHO는 코멘트에 없기 때문에 코드가 실행됩니다.코드는 다음 줄에 있습니다.Java에서는 예상대로 "댓글에서 코드 실행"이 허용되지 않습니다.

대부분의 혼란은 구문 강조 표시기와 IDE가 이러한 상황을 고려할 만큼 정교하지 않다는 사실에서 비롯됩니다.유니코드 이스케이프를 전혀 처리하지 않거나 이전이 아닌 코드를 해석한 후 처리한다.javac한다.

\u000descape는 코멘트를 종료합니다.\u이스케이프는 프로그램이 토큰화되기 전에 해당 유니코드 문자로 균일하게 변환됩니다.동등하게 사용할 수 있습니다.\u0057\u0057대신//코멘트를 시작합니다.

이것은 IDE의 버그입니다.구문을 강조 표시하여 이 행이 다음과 같이 되어 있는지 확인합니다.\u000d코멘트를 종료합니다.

이것도 언어의 설계 오류입니다.지금은 수정할 수 없습니다.그렇게 되면, 거기에 의존하는 프로그램이 망가져 버리기 때문입니다. \uexcape는 컴파일러에 의해 대응하는 Unicode 문자로 변환되어야 합니다.이 문자는 "sense"(문자열 리터럴과 식별자, 그리고 아마도 다른 곳) 또는 U+0000–007F 범위의 문자를 생성하는 것을 금지해야 합니다.이러한 의미론 중 하나가 코멘트가 에 의해 종료되는 것을 막았을 것입니다.\u000d의 경우에 간섭하지 않고 탈옥하다\uexcape가 도움이 됩니다.이것에는, 다음의 기능이 포함됩니다.\u내부 코멘트는 라틴어 이외의 스크립트에서 코멘트를 부호화하는 방법으로 이스케이프합니다.텍스트 에디터는, 다음의 장소를 보다 넓게 볼 수 있기 때문입니다.\uexcape는 컴파일러보다 중요합니다.(표시되는 에디터나 IDE는 없습니다).\u단, 는 임의의 컨텍스트에서 대응하는 문자로 이스케이프됩니다).

C 1패밀리에 유사한 설계 오류가 있습니다. 여기서 주석 경계를 결정하기 전에 백슬래시-뉴라인이 처리됩니다.

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

컴파일러 프로그래머가 토큰화와 파싱에 대해 생각하는 방식에 익숙하다면 이 특정 설계 오류를 범하기 쉽고 수정하기엔 너무 늦었다는 것을 깨닫기 위해 이 문제를 제기합니다.기본적으로 공식 문법을 이미 정의하여 누군가가 구문적인 특수 케이스(삼각문자, 백슬래시-뉴라인, ASCII에 한정된 소스 파일 내의 임의의 Unicode 문자 인코딩 등)를 생각해냈을 경우 토큰라이저 앞에 변환 패스를 추가하는 것이 재정의하는 것보다 쉽습니다.그 특별한 케이스를 사용하는 것이 말이 되는지에 주의를 기울이는 케나이저.

1 소아용:C의 이 측면은 100% 의도적인 것으로 알고 있습니다.이거는 지어낸 것이 아닙니다만, 펀치 카드에 임의의 긴 라인이 있는 코드를 기계적으로 장착할 수 있습니다.그것은 여전히 잘못된 설계 결정이었다.

이는 Java의 원래 디자인으로 거슬러 올라가는 의도적인 디자인 선택이었습니다.

"누가 유니코드 탈출을 원하는가?"라고 묻는 사람들에게 그들은 모국어가 라틴 문자 집합을 사용하는 사람들일 것이다.즉, 자바 프로그램 내에서 합법적으로 임의의 유니코드 문자를 사용할 수 있는 것은 원래 자바 설계에 내재되어 있습니다.대부분은 코멘트나 문자열로 되어 있습니다.

소스 텍스트를 보기 위해 사용되는 프로그램(IDE 등)의 단점으로는 유니코드 이스케이프를 해석하여 대응하는 글리프를 표시할 수 없습니다.

@zwoon의 의견에 동의하지만 더 비판적입니다.

\u이스케이프는 문자열과 문자 리터럴에서 유용하며, 그것이 존재해야 할 유일한 장소입니다.다른 탈옥과 같은 방법으로 처리되어야 합니다\n; 및"\u000A" 정확히 의미해야 한다"\n".

을 갖는 것은 전혀 의미가 없다.\uxxxx댓글로 - 아무도 못 읽어요

마찬가지로, 사용의 의미가 없습니다.\uxxxx프로그램의 다른 부분에서요.유일한 예외는 ASCII가 아닌 문자를 포함하도록 강요된 퍼블릭 API일 것입니다.그것을 마지막으로 본 것은 언제입니까?

디자이너들은 1995년에 그들의 이유가 있었지만, 20년이 지난 지금, 이것은 잘못된 선택으로 보인다.

(독자들에게 하는 질문 - 왜 이 질문은 계속 새로운 표를 얻는가?이 질문은 인기 있는 장소에서 링크된 것입니까?)

유니코드 탈옥이 왜 그대로 구현되었는지를 대답할 수 있는 사람은 규격을 작성한 사람들뿐입니다.

그럴듯한 이유는 Java 소스 코드의 가능한 문자로 BMP 전체를 허용하려는 욕구가 있었기 때문입니다.단, 다음과 같은 문제가 발생합니다.

  • 임의의 BMP 문자를 사용할 수 있어야 합니다.
  • 임의의 BMP 문자를 꽤 간단하게 입력할 수 있도록 하고 싶다.이를 위한 방법은 Unicode 이스케이프를 사용하는 것입니다.
  • 어휘 사양은 사람이 읽고 쓰기 쉽고 구현도 상당히 용이해야 합니다.

Unicode가 탈옥하면 이것은 매우 어려워집니다.이것은 새로운 렉서 규칙을 만들어냅니다.

쉬운 방법은 두 가지 단계로 렉싱을 수행하는 것입니다. 먼저 모든 Unicode 이스케이프를 검색하여 해당 문자가 나타내는 문자로 바꾼 다음 결과 문서를 Unicode 이스케이프가 존재하지 않는 것처럼 해석합니다.

이 방법의 장점은 지정이 용이하기 때문에 사양이 심플해지고 구현이 용이하다는 것입니다.

단점은, 음, 당신의 예시입니다.

"그 이유는 자바 컴파일러가 유니코드 문자 \u000d를 새로운 행으로 해석하기 때문입니다."

참일 경우 오류가 발생하는 지점이 바로 그 지점입니다.

Java 컴파일러는 (Java 소스 코드로서) 이 소스 컴파일러의 컴파일을 거부해야 합니다.이 소스 컴파일러는 (Java 소스 코드로서) 포맷이 잘못되어 처음에 불량하거나 도중에 조작되거나 변환 규칙을 이해하지 못하는 툴 체인 내의 무언가에 의해 변환되기 때문입니다.그들은 그것을 맹목적으로 변형시켜서는 안 된다.

문제의 에디터가 ASCII 전용 툴인 경우, 그 에디터는 Unicode 이스케이프 시퀀스를 (잘못된) 코멘트 내의 의미 없는 문자열로 취급하는 올바른 처리를 하고 있습니다.

문제의 편집기가 Unicode 인식 도구인 경우 Unicode 이스케이프 시퀀스를 그대로 두고 (잘못된) 코멘트 내의 의미 없는 문자열로 취급하는 것도 올바른 방법입니다.

무손실, 가역 변환에는 1-1을 매핑하는 변환이 필요합니다.따라서 두 세트의 교점은 비어 있어야 합니다.여기서 문제의 2개의 세트는 올바르게 구현된 이스케이프-ify-ing 변환에 의해 문자가 변경되지 않더라도 중복될 수 있습니다.이는 입력 스트림 내에 이미 이스케이프 유니코드(000-07F)가 존재할 수 있기 때문입니다.

Unicode와 ASCII 간의 무손실, 가역 변환이 목표인 경우 ASCII로 변환하거나 ASCII에서 변환하는 요건은 16진수 007F보다 큰 Unicode 문자를 이스케이프/재인코딩하고 나머지는 그대로 두는 것입니다.

그 후 Unicode를 인식하는 언어는 이스케이프 유니코드 문자를 코멘트나 문자열 내부 이외의 에러로 취급합니다.코멘트 내에서 변환해서는 안 되지만 문자열 내에서 변환해야 합니다.따라서 변환은 어휘 분석이 소스를 토큰으로 변환한 후에 이루어져야 합니다(즉, 어휘소).s) 변환이 타입 세이프 방식으로 이루어질 수 있도록 한다.

언급URL : https://stackoverflow.com/questions/30727515/why-is-executing-java-code-in-comments-with-certain-unicode-characters-allowed

반응형