다음을 통해 공유


오류: stack-use-after-scope

삭제자 오류 해결: 범위를 벗어난 스택 메모리 사용

변수의 수명 어휘 범위 외부에 스택 주소를 사용하면 C 또는 C++에서 여러 가지 방법으로 발생할 수 있습니다.

예제 1 - 단순 중첩된 로컬

// example1.cpp
// stack-use-after-scope error
int *gp;

bool b = true;

int main() {
    if (b) {
        int x[5];
        gp = x+1;
    }
    return *gp;  // Boom!
}

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

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

결과 오류 - 단순 중첩된 로컬

예제 1에서 스택 사용 후 범위 오류를 표시하는 디버거의 스크린샷

예제 2 - 람다 캡처

// example2.cpp
// stack-use-after-scope error
#include <functional>

int main() {
    std::function<int()> f;
    {
        int x = 0;
        f = [&x]() {
            return x;  // Boom!
        };
    }
    return f();  // Boom!
}

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

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

결과 오류 - 람다 캡처

예제 2에서 스택 사용 후 범위 오류를 표시하는 디버거의 스크린샷.

예제 3 - 지역 주민을 사용하여 소멸자 순서 지정

// example3.cpp
// stack-use-after-scope error
#include <stdio.h>

struct IntHolder {
    explicit IntHolder(int* val = 0) : val_(val) { }
    ~IntHolder() {
        printf("Value: %d\n", *val_);  // Bom!
    }
    void set(int* val) { val_ = val; }
    int* get() { return val_; }

    int* val_;
};

int main(int argc, char* argv[]) {
    // It's incorrect to use "x" inside the IntHolder destructor,
    // because the lifetime of "x" ends earlier. Per the C++ standard,
    // local lifetimes end in reverse order of declaration.
    IntHolder holder;
    int x = argc;
    holder.set(&x);
    return 0;
}

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

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

결과 오류 - 소멸자 순서 지정

예제 3에서 스택 사용 후 범위 오류를 표시하는 디버거의 스크린샷

예제 4 - 임시

// example4.cpp
// stack-use-after-scope error
#include <iostream>

struct A {
    A(const int& v) {
        p = &v;
    }
    void print() {
        std::cout << *p;
    }
    const int* p;
};

void explicit_temp() {
    A a(5);     // the temp for 5 is no longer live;
    a.print();
}

void temp_from_conversion() {
    double v = 5;
    A a(v);     // local v is no longer live.
    a.print();
}

void main() {
    explicit_temp();
    temp_from_conversion(); 
}

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

cl example4.cpp /EHsc /fsanitize=address /Zi /Od
devenv /debugexe example4.exe

ASAN은 동적 분석의 한 형태이므로 실제로 실행되는 잘못된 코드만 검색할 수 있습니다. 최적화 프로그램은 에 저장된 주소에서 읽는 대신 이러한 경우의 v 값을 전파할 수 있습니다 p. 따라서 이 예제에는 플래그가 /Od 필요합니다.

결과 오류 - 임시

예제 4에서 스택 사용 후 범위 오류를 표시하는 디버거의 스크린샷.

참고 항목

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