Partage via


Erreur : stack-use-after-return

Erreur d’assainissement de l’adresse : utilisation de la mémoire de la pile après le retour

Cette vérification nécessite la génération de code activée par une option de compilateur supplémentaire, /fsanitize-address-use-after-returnet en définissant la variable ASAN_OPTIONS=detect_stack_use_after_return=1d’environnement.

Cette vérification peut ralentir considérablement votre application. Considérez le résumé Clang de l’algorithme qui prend en charge l’utilisation après retour et les coûts de performances plus importants.

Important

Si vous créez un fichier objet à l’aide de l’option /fsanitize-address-use-after-returnde compilateur supplémentaire, le code généré par le compilateur prend une décision d’exécution sur la façon d’allouer une trame de pile. Si la variable ASAN_OPTIONS d’environnement n’est pas définie detect_stack_use_after_returnsur , le code est encore plus lent que l’utilisation /fsanitize=address elle-même. Il est plus lent, car il existe encore une surcharge supplémentaire à partir de certaines trames de pile qui allouent de l’espace pour les parties d’un cadre à l’aide alloca()de . Il est préférable de supprimer ces fichiers d’objets lorsque vous avez terminé le traitement des erreurs d’utilisation après retour.

Exemple - Simple C

// example1.cpp
// stack-use-after-return error
volatile char* x;

void foo() {
    char stack_buffer[42];
    x = &stack_buffer[13];
}

int main() {

    foo();
    *x = 42; // Boom!

    return (*x == 42);
}

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 /fsanitize-address-use-after-return /Zi
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example1.exe

Erreur résultante - Simple C

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

Exemple : C++ et modèles

// example2.cpp
// stack-use-after-return error
#include <stdlib.h>

enum ReadOrWrite { Read = 0, Write = 1 };

struct S32 {
    char x[32];
};

template<class T>
T* LeakStack() {
    T t[100];
    static volatile T* x;
    x = &t[0];
    return (T*)x;
}

template<class T>
void StackUseAfterReturn(int Idx, ReadOrWrite w) {
    static T sink;
    T* t = LeakStack<T>();
    if (w)
        t[100 + Idx] = T();
    else
        sink = t[100 + Idx];
}

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

    if (argc != 2) return 1;
    int kind = atoi(argv[1]);

    switch (kind) {
    case 1: StackUseAfterReturn<char>(0, Read); break;
    case 2: StackUseAfterReturn<S32>(0, Write); break;
    }
    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 example2.cpp /fsanitize=address /fsanitize-address-use-after-return /Zi /Od
set ASAN_OPTIONS=detect_stack_use_after_return=1
devenv /debugexe example2.exe 1

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 déterminer que la valeur ou t[100 + Idx] sink n’est jamais utilisée et elide l’affectation. Par conséquent, cet exemple nécessite l’indicateur /Od .

Erreur résultante - C++ et modèles

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

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