AddressSanitizer 섀도 바이트
섀도 바이트의 개념과 런타임 구현 /fsanitize=address
에서 섀도 바이트를 사용하는 방법을 간략하게 요약합니다. 자세한 내용은 초기 연구 AddressSanitizer - Serebryany, et al 및 현재 AddressSanitizer 알고리즘 설명서를 참조하세요.
핵심 개념
애플리케이션의 가상 주소 공간에서 8바이트마다 1개의 섀도 바이트를 사용하여 설명할 수 있습니다.
하나의 섀도 바이트는 다음과 같이 현재 액세스할 수 있는 바이트 수를 설명합니다.
- 0은 8바이트 모두를 의미합니다.
- 1-7은 1~7바이트를 의미합니다.
- 음수는 진단을 보고하는 데 사용할 런타임의 컨텍스트를 인코딩합니다.
섀도 바이트 범례
모든 음수가 정의된 이 섀도 바이트 범례를 고려합니다.
매핑 - 주소 공간 설명
애플리케이션의 가상 주소 공간에서 "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 오류 예제