Effective Debugging/Chatper 6. 컴파일 시간 기법

created : 2020-04-07T11:44:40+00:00
modified : 2020-09-26T14:28:28+00:00

Item 50. 생성된 코드 확인하기

  • 컴파일러에서 생성한 코드를 살펴보면 컴팡리 및 실행 시간에 발생한 문제가 소스 코드의 어느 부분에 관련이 있는지 찾아낼 수 있다.
  • 컴파일러로 생성된 코드를 좀 더 읽기 좋게 표현하려면 컴파일러에 적절한 옵션을 지정하거나 특수한 도구를 사용한다.

Item 51. 정적 분석 도구 활용하기

자주하는 실수 모음

  • 널 포인터 참조
  • 동시성 오류 및 경쟁 상태
  • 철자 오류 (변수를 명시적으로 선언하지 않아도 되는 언어에서 주로 발생함)
  • 배열이나 메모리 버퍼에 대한 잘못된 인덱스 참조
  • 잘못된 조건문, 반복문, case문으로 인해 실행될 수 없는 문장
  • 처리하지 않은 예외
  • 사용하지 않는 변수나 루틴
  • 수식 오류
  • 중복된 코드
  • C++에서의 3의 법칙이나 0의 법칙을 따르지 않거나, 자바에서 클래스를 정의할 때 equals/HashCode 메서드를 일고나성이 없는 형태로 구현한 경우
  • 자원 누수
  • 보안 취약점
  • 문법 오류

기억할 사항

  • 정적 프로그램 분석 도구를 활용하면 컴파일러 경고 메시지로 찾지 못한 잠재적인 버그를 발견할 수 있다.
  • 프로그램에 존재하는 버그를 분석하기 좋도록 컴파일러 옵션을 적절히 설정한다.
  • 빌드 과정과 지속적인 통합 과정에 최소한 한 개 이상의 정적 프로그램 분석 도구를 거치도록 설정한다.

Item 52. 빌드 결과와 실행 동작이 항상 일정하도록 설정하기

  • 악의적인 공격을 막기 위해 OS 커널이 프로그램이 올라갈 메모리의 위치에 대한 주소 값을 난수로 정한다. (ALSR, Address Space Layout Randomization)
  • GNU/Linux 에서는
    setarch $(uname -m) -R myprogram
    
  • Visual Studio에서는 /DYNAMICBASE:NO 옵션을 지정한다.

  • 컴파일러는 기호 이름을 결과 파일에 넣을 때 임의로 생성한 값을 사용한다. GCC에서 -frandom-seed 플래그를 지정하면 이 값을 고정할 수 있다.
  • 컴파일러에 입력한 값의 순서가 변한다. 컴파일하거나 링크할 파일을 Makefile에서 와일드카드 형태로 지정했다면 빌드할 때마다 실제로 파일이 입력되는 순서가 달라진다. 입력값을 명시적으로 지정하거나, 와일드카드로 입력할 항목을 정렬하면 순서를 일정하게 유지할 수 있다.
  • __DATE____TIME__ 매크로를 이용하여 소프트웨어의 버전을 타밍스탬프 값으로 표기하도록 코드를 작성했다면 이 값도 매번 달라진다. 타임스탬프 대신 버전관리 시스템의 식별자를 사용하면 고정할 수 있다.
  • 해시나 맵을 통해 생성한 리스트도 변한다. 어떤 컴파일러는 알고리즘 복잡도 공격을 막기 위해 객체에 대한 해시 방식도 바꾼다.
  • 어떤 값을 암호화 하는 과정에서 salt를 추가하기도 한다. 이렇게 하면 dictionary attacks을 어느 정도 막을 수 있다. 단, 코드를 디버깅할 때는 꺼두는게 좋다.

Item 53. 라이브러리에서 제공하는 디버깅 및 검사 기능 설정하기

기억할 사항

  • 현재 개발 환경의 컴파일러와 라이브러리에서 제공하는 런타임 디버깅 기능을 찾아서 적극 활용한다.
  • 현재 환경에서 제공되는 런타임 디버깅 기능이 없다면 이를 제공하는 서드파티 라이브러리를 사용하도록 설정한다.