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();
}
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 -m32 test.cpp -fsanitize=address