Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ASAN] [x86] Thrown exceptions corrupt stack near catch site #54804

Open
amyw-msft opened this issue Apr 7, 2022 · 1 comment
Open

[ASAN] [x86] Thrown exceptions corrupt stack near catch site #54804

amyw-msft opened this issue Apr 7, 2022 · 1 comment
Labels

Comments

@amyw-msft
Copy link
Contributor

When an exception is thrown with AddressSanitizer in use, the x86 compiler fails to take into account stack red-zones added for catch bodies when determining variable addresses. Below are five examples.

>clang --version
clang version 14.0.0
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files (x86)\LLVM\bin

> clang -m32 test.cpp -fsanitize=address

#include <stdio.h>

void one() {
    // Set variables before and after caught exception.
    // Variable set after thrown exception is corrupted.
    puts("one");
    int test = 5;

    try {
        throw 42;
    } catch (...) {
    }

    int test2 = 10;

    printf("%p : %d\n", &test, test);
    printf("%p : %d\n", &test2, test2);
    // 014FFA10 : 5
    // 014FFA30 : 7213915 <-- should be 10
}

void two() {
    puts("two");
    // Expanding amount of stack variables show that the next 16 bytes are corrupted.
    int test = 5;

    try {
        throw 42;
    } catch (...) {
    }

    int vars[5] = {10, 15, 20, 25, 30};

    printf("%p : %d\n", &test, test);
    for (int& x : vars) {
        printf("%p : %d\n", &x, x);
    }
    // 014FF9F0 : 5
    // 014FFA00 : 67108874 <-- should be 10
    // 014FFA04 : 0        <-- should be 15 (always 0)
    // 014FFA08 : 22018464 <-- should be 20
    // 014FFA0C : 0        <-- should be 25 (always 0)
    // 014FFA10 : 30
}

void three() {
    puts("three");
    // Without the first variable set prior to exception throw, only 4 bytes are corrupted.
    try {
        throw 42;
    } catch (...) {
    }

    int vars[5] = {10, 15, 20, 25, 30};

    for (int& x : vars) {
        printf("%p : %d\n", &x, x);
    }

    // 014FFA00 : 10
    // 014FFA04 : 22018464 <-- should be 15
    // 014FFA08 : 20
    // 014FFA0C : 25
    // 014FFA10 : 30
}

void four() {
    puts("four");
    // Moving all variables before thrown exception corrupt in a different pattern.

    int vars[5] = {10, 15, 20, 25, 30};

    try {
        throw 42;
    } catch (...) {
    }

    for (int& x : vars) {
        printf("%p : %d\n", &x, x);
    }
    // 014FF9F0 : 10
    // 014FF9F4 : 0        <-- should be 15 (always 0)
    // 014FF9F8 : 22018464 <-- should be 20
    // 014FF9FC : 0        <-- should be 25 (always 0)
    // 014FFA00 : 30
}

void five() {
    puts("five");
    // Before and after also corrupt in a unique pattern.

    int vars[5] = {10, 15, 20, 25, 30};

    try {
        throw 42;
    } catch (...) {
    }

    int vars2[5] = {35, 40, 45, 50, 55};

    for (int& x : vars) {
        printf("%p : %d\n", &x, x);
    }

    for (int& x : vars2) {
        printf("%p : %d\n", &x, x);
    }
    // 014FF990 : 10
    // 014FF994 : 15
    // 014FF998 : 20
    // 014FF99C : 0        <-- should be 25 (always 0)
    // 014FF9A0 : 30
    // 014FF9E0 : 35
    // 014FF9E4 : 22018432 <-- should be 40
    // 014FF9E8 : 20       <-- should be 45 (always 20)
    // 014FF9EC : 50
    // 014FF9F0 : 55
}

int main() {
    one();
    two();
    three();
    four();
    five();
}
@llvmbot
Copy link
Member

llvmbot commented Apr 7, 2022

@llvm/issue-subscribers-backend-x86

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants