연결할 수 없는 코드

Unreachable code

컴퓨터 프로그래밍에서, 도달할 수 없는 코드는 프로그램의 소스 코드의 일부로서 프로그램의 나머지 부분으로부터 코드에 대한 제어 흐름 경로가 존재하지 않기 때문에 결코 실행될 수 없다.[1]

접속 불가능한 코드는 데드 코드라고도 부르지만 데드 코드는 실행되지만 프로그램 출력에 영향을 미치지 않는 코드를 가리킬 수도 있다.[2][3][4]

연결할 수 없는 코드는 일반적으로 다음과 같은 몇 가지 이유로 바람직하지 않은 것으로 간주된다.

  • 불필요하게 메모리를 사용한다.
  • CPU의 명령 캐시를 불필요하게 사용할 수 있음
  • 사용하지 않는 코드를 테스트, 유지관리 및 문서화하는 데 시간과 노력이 소요될 수 있음
    • 때때로 자동화된 테스트만이 코드를 사용하는 것이다.

그러나, 접속할 수 없는 코드는 프로그램이 중단되고 나서 중단되는 동안 디버거를 통해 수동으로 호출하거나 점프하는 기능의 라이브러리를 제공하는 것과 같은 합법적인 용도를 가질 수 있다.이것은 특히 프로그램의 내부 상태를 조사하고 예쁘게 인쇄하는 데 유용하다.개발자가 클라이언트의 실행 중인 인스턴스에 디버거를 부착할 수 있도록 출하된 제품에 그러한 코드가 있는 것이 타당할 수 있다.

원인들

연결할 수 없는 코드는 다음과 같은 여러 가지 이유로 존재할 수 있다.

  • 복잡한 조건부 분기의 프로그래밍 오류
  • 최적 컴파일러가 수행하는 내부 변환의 결과
  • 새 코드 또는 수정된 코드의 불완전한 테스트
  • 레거시 코드
    • 다른 구현으로 대체된 코드
    • 프로그래머가 도달 가능한 코드와 섞여 있어 삭제하지 않기로 결정한 접속 불가 코드
    • 현재 사용 사례에 전혀 필요하지 않은 잠재적으로 도달할 수 있는 코드
    • 나중에 필요할 경우에 대비하여 의도적으로 보관하는 휴면 코드
  • 디버깅에만 사용되는 코드.

레거시 코드는 한때 유용했지만 더 이상 사용하거나 요구되지 않는 코드다.그러나 연결할 수 없는 코드는 다른 사람에게 유용하거나 특정 시나리오에서 충족되지 않는 조건에서 다른 사람에게 유용한 복잡한 라이브러리, 모듈 또는 루틴의 일부일 수도 있다.

조건적으로 접근할 수 없는 코드의 예로는 컴파일러의 런타임 라이브러리에서 일반 문자열 포맷 기능의 구현이 있을 수 있으며, 여기에는 가능한 모든 인수를 처리하기 위한 복잡한 코드가 포함되어 있으며, 이 중 작은 부분 집합만 실제로 사용된다.실행 시간의 인수 값에 의해 동작이 결정되기 때문에 컴파일러는 일반적으로 컴파일 시간에 사용하지 않는 코드 섹션을 제거할 수 없다.

이 C 코드 조각에서:

인트로 foo (인트로 X, 인트로 Y) {     돌아오다 X + Y;     인트로 Z = X * Y; } 

정의{{{1}}}}은(는) 기능이 항상 그 전에 돌아오기 때문에 결코 도달하지 않는다.따라서 Z는 스토리지를 할당하거나 초기화할 필요가 없다.

goto fail bug.

2014년 2월 애플의 SSL/TLS에는 공식적으로 CVE-로 알려진 중대한 보안 결함이 있었다.2014-1266년 비공식적으로 "고토 장애 버그"로 지정됨.[5][6]관련 코드 조각[7]:

정태의 OSTatus SSLVerifySignedServerKey교환(SSLContext *ctx, 바가지 긁다 이스르사, SSL부퍼 signedParams,                                  uint8_t *서명하다, UInt16 시그니처렌) {     OSTatus        잘못을 저지르다;     ...       만일 ((잘못을 저지르다 = SSLHASHSHA1.갱신하다(&hashCtx, &serverRandom)) != 0)         에 가다 실패하다;     만일 ((잘못을 저지르다 = SSLHASHSHA1.갱신하다(&hashCtx, &signedParams)) != 0)         에 가다 실패하다;         에 가다 실패하다;     만일 ((잘못을 저지르다 = SSLHASHSHA1.최종의(&hashCtx, &해시아웃)) != 0)         에 가다 실패하다;     ...   실패하다:     SSLFreeBuffer(&서명된 해시);     SSLFreeBuffer(&hashCtx);     돌아오다 잘못을 저지르다; } 

여기서, 두 차례 연속해서 에 대한 전화가 걸려온다.goto fail. C 언어의 구문에서는, 두 번째는 무조건적이며, 따라서 항상 다음 호를 생략한다.SSLHashSHA1.final그 결과,errSHA1 업데이트 작업의 상태를 유지하며 서명 검증은 절대 실패할 수 없다.[5]

여기서, 연결할 수 없는 코드는 전화에 대한 호출이다.final기능을 발휘하다코드 검토, 들여쓰기 또는 블록 구조의 적절한 사용, 시험 범위 분석 등 이 결함을 막을 수 있었던 몇 가지 코딩 관행이 있다.[6]옵션을 사용하여 Crang 컴파일러 적용-Weverything이 코드에 대해 경보를 트리거할 수 있는 연결할 수 없는 코드 분석을 포함한다.[6]

C++

C++에서 일부 구조는 정의되지 않은 동작을 갖도록 지정된다.컴파일러는 어떤 행동이나 어떤 행동도 자유롭게 구현할 수 있으며, 일반적으로 최적화 컴파일러는 코드에 연결할 수 없다고 가정한다.[8]

분석

도달할 수 없는 코드의 검출은 가능한 프로그램 상태에서는 절대 도달할 수 없는 코드를 찾기 위한 제어 흐름 분석의 한 형태다.일부 언어([9]: Java)에서는 연결할 수 없는 코드의 일부 형식은 명시적으로 허용되지 않는다.연결할 수 없는 코드를 제거하는 최적화를 데드 코드 제거라고 한다.

최적화 컴파일러에 의해 수행된 변환의 결과로 코드에 접근할 수 없게 될 수 있다(예: 공통 하위 표현 제거).

실제로 분석의 정교화는 감지되는 도달할 수 없는 코드의 양에 상당한 영향을 미친다.예를 들어, 지속적인 접기 및 단순 흐름 분석을 통해 다음 코드의 if-statement 내부에 연결할 수 없음을 알 수 있다.

인트로 N = 2 + 1;  만일 (N == 4) {    /* 연결할 수 없음 */ } 

그러나 다음 코드에서 해당 블록에 접근할 수 없다는 것을 알아내기 위해서는 훨씬 더 정교함이 필요하다.

곱절로 하다 X = sqrt(2);  만일 (X > 5) {     /* 연결할 수 없음 */ } 

도달할 수 없는 코드 제거 기술은 데드 코드 제거중복 코드 제거와 동일한 종류의 최적화에 있다.

비접근성 vs 프로파일링

경우에 따라 실무적 접근방식은 단순한 비접근성 기준과 보다 복잡한 사례를 처리하기 위한 프로파일러의 사용일 수 있다.일반적으로 프로파일링은 코드 조각의 비접근성에 대해 어떤 것도 증명할 수 없지만, 잠재적으로 접근할 수 없는 코드를 찾으려면 좋은 경험적 발견이 될 수 있다.일단 의심스러운 코드가 발견되면, 더 강력한 코드 분석 도구 또는 심지어 손으로 분석하는 것과 같은 다른 방법을 사용하여 코드에 실제로 접근할 수 없는지를 결정할 수 있다.

참고 항목

참조

  1. ^ Debray, Saumya K.; Evans, William; Muth, Robert; De Sutter, Bjorn (1 March 2000). "Compiler techniques for code compaction". ACM Transactions on Programming Languages and Systems. 22 (2): 378–415. CiteSeerX 10.1.1.43.7215. doi:10.1145/349214.349233. S2CID 6129772.
  2. ^ RTCA/DO-178C Software Considerations in Airborne Systems and Equipment Certification. RTCA, Inc. 2011. p. 112. Retrieved 2019-06-11. Dead code – Executable Object Code (or data) which exists as a result of a software development error but cannot be executed (code) or used (data) in any operational configuration of the target computer environment. It is not traceable to a system or software requirement. The following exceptions are often mistakenly categorized as dead code but are necessary for implementation of the requirements/design: embedded identifiers, defensive programming structures to improve robustness, and deactivated code such as unused library functions. [Since requirements-based review should identified such code as untraceable to functional requirements, static code analysis should identify such code as unreachable, and structural coverage analysis of requirements-based testing results should identify such code as unreachable, presence of unjustified dead code in a project should raise consideration of the effectiveness of the organization’s development and verification processes.]
  3. ^ Jay Thomas (24 January 2017). "Requirements Traceability Forms the Foundation for Thorough Software Testing". Retrieved 2019-06-11. The combination of requirements traceability with coverage analysis can also turn up areas of “dead code,” or code that’s never executed. This code can mostly be an inconvenience, but it can also be a security threat if a hacker can gain access and from there gain control. It’s code that can’t be traced and should therefore be eliminated.
  4. ^ MISRA Consortium (March 2013). MISRA C:2012 Guidelines for the used of C language in critical systems. MIRA Limited. p. 41. Retrieved 2019-06-11. Rule 2.2 there shall be no dead code. Any operation that is executed but whose removal would not affect program behavior constitutes dead code.
  5. ^ a b Adam Langley (2014). "Apple's SSL/TLS bug".
  6. ^ a b c Arie van Deursen (2014). "Learning from Apple's #gotofail Security Bug".
  7. ^ "sslKeyExchange.c - Source code for support for key exchange and server key exchange".
  8. ^ "MSC15-C. Do not depend on undefined behavior". Carnegie Mellon University. 2020. Retrieved 28 September 2020. Because compilers are not obligated to generate code for undefined behavior, these behaviors are candidates for optimization.
  9. ^ "Java Language Specification".
  • Appel, A. W. 1998 Modern Compiler Implementation in Java. Cambridge University Press.
  • Muchnick S. S. 1997 Advanced Compiler Design and Implementation. Morgan Kaufmann.