Skip to content

Instantly share code, notes, and snippets.

@Verdagon
Last active December 15, 2025 18:00
Show Gist options
  • Select an option

  • Save Verdagon/4102fecf6dadb7a4802131789b6cc792 to your computer and use it in GitHub Desktop.

Select an option

Save Verdagon/4102fecf6dadb7a4802131789b6cc792 to your computer and use it in GitHub Desktop.
#include <memory>
#include <variant>
#include <iostream>
struct Engine {
int fuel;
Engine(int fuel_) : fuel(fuel_) {}
};
struct Spaceship {
std::variant<bool, std::unique_ptr<Engine>> v;
Spaceship(std::variant<bool, std::unique_ptr<Engine>> v_) :
v(std::move(v_)) {}
void print() {
// Print the contents of ship
if (std::holds_alternative<std::unique_ptr<Engine>>(v)) {
auto& engineRef = std::get<std::unique_ptr<Engine>>(v);
std::cout << "Fuel: " << engineRef->fuel << std::endl; // Segfault at address 0x1!
} else if (std::holds_alternative<bool>(v)) {
bool& boolRef = std::get<bool>(v);
std::cout << "Spaceship.v.bool: " << boolRef << std::endl; // Segfault at address 0x1!
}
}
};
void maintenance(std::shared_ptr<Spaceship> ship) {
// Circuitous shapeshift: changes ship->v to hold Engine pointer
ship->v = std::make_unique<Engine>(Engine{100});
}
void foo(std::shared_ptr<Spaceship> ship) {
if (std::holds_alternative<bool>(ship->v)) {
bool& boolRef = std::get<bool>(ship->v); // Reference, not pointer!
maintenance(ship); // Changes ship->v to hold Engine pointer
boolRef = true; // Writes to invalid memory through the reference
}
}
int main() {
auto ship =
std::make_shared<Spaceship>(
std::variant<bool, std::unique_ptr<Engine>>{true});
foo(ship);
ship->print();
}
// verdagon@Evans-MBP ~ % clang++ -fsanitize=address circshapeshift.cpp && ./a.out
// a.out(27971,0x2027b7ac0) malloc: nano zone abandoned due to inability to reserve vm space.
// =================================================================
// ==27971==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000001 at pc 0x00010216d770 bp 0x00016dc93050 sp 0x00016dc93048
// READ of size 4 at 0x602000000001 thread T0
// #0 0x00010216d76c in Spaceship::print()+0xa4 (a.out:arm64+0x10000176c)
// #1 0x00010216d2c8 in main+0x1cc (a.out:arm64+0x1000012c8)
// #2 0x00019a7220dc (<unknown module>)
// #3 0x5275fffffffffffc (<unknown module>)
//
// 0x602000000001 is located 15 bytes before 16-byte region [0x602000000010,0x602000000020)
// freed by thread T0 here:
// #0 0x0001029a7494 in free+0x70 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x3f494)
// #1 0x00019a6d0c8c in _NXHashRehashToCapacity+0xd0 (libobjc.A.dylib:arm64+0x4c8c)
// #2 0x5b0480019a6d0ba0 (<unknown module>)
// #3 0xe42200019a6eb2c0 (<unknown module>)
// #4 0x750c00019a6eb0dc (<unknown module>)
// #5 0x7e5e00019a6cf7d0 (<unknown module>)
// #6 0x2a7380019a6ce8e8 (<unknown module>)
// #7 0xb35b80019a732d0c (<unknown module>)
// #8 0xaa7980019a72961c (<unknown module>)
// #9 0xa00880019a7304d0 (<unknown module>)
// #10 0xb6a00019a753eb8 (<unknown module>)
// #11 0x491c00019a6ce658 (<unknown module>)
// #12 0x205d80019a8f9724 (<unknown module>)
// #13 0x6a4880019a909178 (<unknown module>)
// #14 0x123f8001a771b63c (<unknown module>)
// #15 0x12500019a73d058 (<unknown module>)
// #16 0x3c0500019a77b304 (<unknown module>)
// #17 0x572680019a76e998 (<unknown module>)
// #18 0x40780019a71e2f8 (<unknown module>)
// #19 0x110d00019a76d92c (<unknown module>)
// #20 0xd26100019a77ae18 (<unknown module>)
// #21 0xb43280019a73906c (<unknown module>)
// #22 0x861e80019a742d24 (<unknown module>)
// #23 0xb41380019a75c358 (<unknown module>)
// #24 0xfc7780019a722f78 (<unknown module>)
// #25 0x806500019a721ed8 (<unknown module>)
// #26 0x5275fffffffffffc (<unknown module>)
//
// previously allocated by thread T0 here:
// #0 0x0001029a7678 in calloc+0x74 (libclang_rt.asan_osx_dynamic.dylib:arm64+0x3f678)
// #1 0x00019a6eb234 in NXCreateHashTable+0x6c (libobjc.A.dylib:arm64+0x1f234)
// #2 0x750c00019a6eb0dc (<unknown module>)
// #3 0x7e5e00019a6cf7d0 (<unknown module>)
// #4 0x2a7380019a6ce8e8 (<unknown module>)
// #5 0xb35b80019a732d0c (<unknown module>)
// #6 0xaa7980019a72961c (<unknown module>)
// #7 0xa00880019a7304d0 (<unknown module>)
// #8 0xb6a00019a753eb8 (<unknown module>)
// #9 0x491c00019a6ce658 (<unknown module>)
// #10 0x205d80019a8f9724 (<unknown module>)
// #11 0x6a4880019a909178 (<unknown module>)
// #12 0x123f8001a771b63c (<unknown module>)
// #13 0x12500019a73d058 (<unknown module>)
// #14 0x3c0500019a77b304 (<unknown module>)
// #15 0x572680019a76e998 (<unknown module>)
// #16 0x40780019a71e2f8 (<unknown module>)
// #17 0x110d00019a76d92c (<unknown module>)
// #18 0xd26100019a77ae18 (<unknown module>)
// #19 0xb43280019a73906c (<unknown module>)
// #20 0x861e80019a742d24 (<unknown module>)
// #21 0xb41380019a75c358 (<unknown module>)
// #22 0xfc7780019a722f78 (<unknown module>)
// #23 0x806500019a721ed8 (<unknown module>)
// #24 0x5275fffffffffffc (<unknown module>)
//
// SUMMARY: AddressSanitizer: heap-buffer-overflow (a.out:arm64+0x10000176c) in Spaceship::print()+0xa4
// Shadow bytes around the buggy address:
// 0x601ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 0x601ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 0x601ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 0x601fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// 0x601fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// =>0x602000000000:[fa]fa fd fd fa fa fd fd fa fa 00 00 fa fa 00 fa
// 0x602000000080: fa fa 00 04 fa fa fd fd fa fa 00 00 fa fa 04 fa
// 0x602000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
// 0x602000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
// 0x602000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
// 0x602000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
// Shadow byte legend (one shadow byte represents 8 application bytes):
// Addressable: 00
// Partially addressable: 01 02 03 04 05 06 07
// Heap left redzone: fa
// Freed heap region: fd
// Stack left redzone: f1
// Stack mid redzone: f2
// Stack right redzone: f3
// Stack after return: f5
// Stack use after scope: f8
// Global redzone: f9
// Global init order: f6
// Poisoned by user: f7
// Container overflow: fc
// Array cookie: ac
// Intra object redzone: bb
// ASan internal: fe
// Left alloca redzone: ca
// Right alloca redzone: cb
// ==27971==ABORTING
// Fuel: zsh: abort ./a.out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment