分享方式:


錯誤: 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 - Lambda 擷取

// 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

產生的錯誤 - Lambda 擷取

顯示範例 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 錯誤範例