Partager via


Erreur : stack-use-after-scope

Erreur d’assainissement de l’adresse : utilisation de la mémoire de la pile hors portée

L’utilisation d’une adresse de pile en dehors de l’étendue lexicale de la durée de vie d’une variable peut se produire de nombreuses façons en C ou C++.

Exemple 1 : local imbriqué simple

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

Pour générer et tester cet exemple, exécutez ces commandes dans une invite de commandes développeur Visual Studio 2019 version 16.9 ou ultérieure :

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

Erreur résultante - local imbriqué simple

Capture d’écran du débogueur affichant l’erreur stack-use-after-scope dans l’exemple 1.

Exemple 2 - Capture 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!
}

Pour générer et tester cet exemple, exécutez ces commandes dans une invite de commandes développeur Visual Studio 2019 version 16.9 ou ultérieure :

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

Erreur résultante - capture lambda

Capture d’écran du débogueur affichant l’erreur stack-use-after-scope dans l’exemple 2.

Exemple 3 : classement de destructeur avec les variables locales

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

Pour générer et tester cet exemple, exécutez ces commandes dans une invite de commandes développeur Visual Studio 2019 version 16.9 ou ultérieure :

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

Erreur résultante : classement de destructeur

Capture d’écran du débogueur affichant l’erreur stack-use-after-scope dans l’exemple 3.

Exemple 4 : temporaires

// 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(); 
}

Pour générer et tester cet exemple, exécutez ces commandes dans une invite de commandes développeur Visual Studio 2019 version 16.9 ou ultérieure :

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

ASAN est une forme d’analyse dynamique, ce qui signifie qu’il ne peut détecter que le code incorrect qui est réellement exécuté. Un optimiseur peut propager la valeur de v dans ces cas au lieu de lire à partir de l’adresse stockée dans p. Par conséquent, cet exemple nécessite l’indicateur /Od .

Erreur résultante : temporaires

Capture d’écran du débogueur affichant l’erreur stack-use-after-scope dans l’exemple 4.

Voir aussi

Vue d’ensemble de AddressSanitizer
Résoudre les problèmes connus liés à AddressSanitizer
Référence de build et de langage AddressSanitizer
Informations de référence sur le runtime AddressSanitizer
Octets d’ombre AddressSanitizer
Test cloud ou distribué AddressSanitizer
Intégration du débogueur AddressSanitizer
Exemples d’erreur AddressSanitizer