다음을 통해 공유


AddressSanitizer 섀도 바이트

섀도 바이트의 개념과 런타임 구현 /fsanitize=address에서 섀도 바이트를 사용하는 방법을 간략하게 요약합니다. 자세한 내용은 초기 연구 AddressSanitizer - Serebryany, et al현재 AddressSanitizer 알고리즘 설명서를 참조하세요.

핵심 개념

애플리케이션의 가상 주소 공간에서 8바이트마다 1개의 섀도 바이트를 사용하여 설명할 수 있습니다.

하나의 섀도 바이트는 다음과 같이 현재 액세스할 수 있는 바이트 수를 설명합니다.

  • 0은 8바이트 모두를 의미합니다.
  • 1-7은 1~7바이트를 의미합니다.
  • 음수는 진단을 보고하는 데 사용할 런타임의 컨텍스트를 인코딩합니다.

섀도 바이트 범례

모든 음수가 정의된 이 섀도 바이트 범례를 고려합니다.

AddressSanitizer 섀도바이트 범례의 스크린샷.

매핑 - 주소 공간 설명

애플리케이션의 가상 주소 공간에서 "0-mod-8"로 정렬된 8바이트마다 가상 주소 공간의 해당 슬롯을 설명하는 섀도 바이트에 매핑할 수 있습니다. 이 매핑은 간단한 시프트 및 추가를 통해 수행할 수 있습니다.

x86에서:

char shadow_byte_value = *((Your_Address >> 3) + 0x30000000)

x64:

char shadow_byte_value = *((Your_Address >> 3) + _asan_runtime_assigned_offset)

코드 생성 - 테스트

컴파일러에서 생성된 코드, 정적 데이터 또는 런타임을 통해 특정 섀도 바이트를 작성하는 방법을 고려합니다. 이 의사 코드는 로드 또는 저장소 앞에 있는 검사를 생성하는 방법을 보여 줍니다.

ShadowAddr = (Addr >> 3) + Offset;
if (*ShadowAddr != 0) {
    ReportAndCrash(Addr);
}

너비가 8바이트 미만인 메모리 참조를 계측하는 경우 계측이 약간 더 복잡합니다. 그림자 값이 양수인 경우(8바이트 단어의 첫 번째 k 바이트만 액세스할 수 있음) 주소의 마지막 3비트를 k와 비교해야 합니다.

ShadowAddr = (Addr >> 3) + Offset;
k = *ShadowAddr;
if (k != 0 && ((Addr & 7) + AccessSize > k)) {
    ReportAndCrash(Addr);
}

런타임 및 컴파일러 생성 코드는 모두 섀도 바이트를 씁니다. 이러한 섀도 바이트는 범위가 종료되거나 스토리지가 해제될 때 액세스를 허용하거나 취소합니다. 위의 검사는 프로그램 실행 시 특정 시간에 애플리케이션의 주소 공간에서 8바이트 "슬롯"을 설명하는 섀도 바이트를 읽습니다. 이러한 명시적으로 생성된 검사 외에도 런타임은 CRT에서 많은 함수를 가로채고(또는 "후크") 후 섀도 바이트를 확인합니다.

자세한 내용은 가로채는 함수 목록을 참조하세요.

섀도 바이트 설정

컴파일러가 생성하는 코드와 AddressSanitizer 런타임 모두 섀도 바이트를 작성할 수 있습니다. 예를 들어 컴파일러는 내부 범위에 정의된 스택 로컬에 대한 고정 크기 액세스를 허용하도록 섀도 바이트를 설정할 수 있습니다. 런타임은 데이터 섹션의 전역 변수를 섀도 바이트로 둘러싸는 데 사용할 수 있습니다.

참고 항목

AddressSanitizer 개요
AddressSanitizer 알려진 문제
AddressSanitizer 빌드 및 언어 참조
AddressSanitizer 런타임 참조
AddressSanitizer 클라우드 또는 분산 테스트
AddressSanitizer 디버거 통합
AddressSanitizer 오류 예제