다음을 통해 공유


오류: global-buffer-overflow

삭제자 오류 해결: 전역 버퍼 오버플로

컴파일러는 또는 .bss 섹션의 변수에 대한 메타데이터를 .data 생성합니다. 이러한 변수에는 전역 또는 파일 정적 언어 범위가 있습니다. 시작하기 전에 main() 메모리에 할당됩니다. C의 전역 변수는 C++에서와 매우 다르게 처리됩니다. 이 차이는 C를 연결하기 위한 복잡한 규칙 때문입니다.

C에서는 여러 소스 파일에서 전역 변수를 선언할 수 있으며 각 정의에는 서로 다른 형식이 있을 수 있습니다. 컴파일러에서 가능한 모든 정의를 한 번에 볼 수는 없지만 링커는 볼 수 있습니다. C의 경우 링커는 기본적으로 다른 모든 선언 중에서 가장 큰 크기의 변수를 선택합니다.

C++에서 전역은 컴파일러에 의해 할당됩니다. 하나의 정의만 있을 수 있으므로 각 정의의 크기는 컴파일 시간에 알려져 있습니다.

예제 - 여러 형식 정의가 있는 'C'의 전역

// file: a.c
int x;
// file: b.c
char* x;
// file: c.c
float* x[3];
// file: example1-main.c
// global-buffer-overflow error

// AddressSanitizer reports a buffer overflow at the first line
// in function main() in all cases, REGARDLESS of the order in 
// which the object files: a.obj, b.obj, and c.obj are linked.
  
double x[5];
 
int main() { 
    int rc = (int) x[5];  // Boom!
    return rc; 
}

이 예제를 빌드하고 테스트하려면 Visual Studio 2019 버전 16.9 이상 개발자 명령 프롬프트에서 다음 명령을 실행합니다.

cl a.c b.c c.c example1-main.c /fsanitize=address /Zi
devenv /debugexe example1-main.exe

결과 오류

예제 1에서 전역 버퍼 오버플로 오류를 표시하는 디버거의 스크린샷

예 - 단순 함수 수준 정적

// example2.cpp
// global-buffer-overflow error
#include <string.h>

int 
main(int argc, char **argv) {

    static char XXX[10];
    static char YYY[10];
    static char ZZZ[10];

    memset(XXX, 0, 10); memset(YYY, 0, 10); memset(ZZZ, 0, 10);

    int res = YYY[argc * 10];  // Boom!

    res += XXX[argc] + ZZZ[argc];
    return res;
}

이 예제를 빌드하고 테스트하려면 Visual Studio 2019 버전 16.9 이상 개발자 명령 프롬프트에서 다음 명령을 실행합니다.

cl example2.cpp /fsanitize=address /Zi
devenv /debugexe example2.exe

결과 오류 - 단순 함수 수준 정적

예제 2에서 전역 버퍼 오버플로 오류를 표시하는 디버거의 스크린샷

예제 - C++의 모든 전역 범위

// example3.cpp
// global-buffer-overflow error

// Run 4 different ways with the choice of one of these options:
//
// -g : Global
// -c : File static
// -f : Function static
// -l : String literal

#include <string.h>

struct C {
    static int array[10];
};

// normal global
int global[10];

// class static
int C::array[10];

int main(int argc, char **argv) {

    int one = argc - 1;

    switch (argv[1][1]) {
    case 'g': return global[one * 11];     //Boom! simple global
    case 'c': return C::array[one * 11];   //Boom! class static
    case 'f':
    {
        static int array[10] = {};
        return array[one * 11];            //Boom! function static
    }
    case 'l':
        // literal global ptr created by compiler
        const char *str = "0123456789";
        return str[one * 11];              //Boom! .rdata string literal allocated by compiler
    }
    return 0;
}

이 예제를 빌드하고 테스트하려면 Visual Studio 2019 버전 16.9 이상 개발자 명령 프롬프트에서 다음 명령을 실행합니다.

cl example3.cpp /fsanitize=address /Zi
devenv /debugexe example3.exe -l

결과 오류 - C++의 모든 전역 범위

예제 3에서 전역 버퍼 오버플로 오류를 표시하는 디버거의 스크린샷

참고 항목

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