Skip to content

Instantly share code, notes, and snippets.

@pavel-kirienko
Created May 26, 2025 19:56
Show Gist options
  • Save pavel-kirienko/f04058defcb21a9f20391e2faa5681d5 to your computer and use it in GitHub Desktop.
Save pavel-kirienko/f04058defcb21a9f20391e2faa5681d5 to your computer and use it in GitHub Desktop.
A simple utility class for debugging stack memory corruption.
#include <cassert>
#include <cstdint>
#include <cstdlib>
namespace stack_canary
{
/// Do not use this directly; see the StackCanary definition below.
template <std::size_t n_bytes, std::uint8_t seed = 0xC9>
class StackCanary_Impl final
{
public:
constexpr StackCanary_Impl() noexcept
{
for (std::size_t i = 0; i < n_bytes; ++i)
{
data_[i] = reference(i);
}
ensure();
}
StackCanary_Impl(const StackCanary_Impl&) = delete;
StackCanary_Impl& operator=(const StackCanary_Impl&) = delete;
StackCanary_Impl(StackCanary_Impl&&) = delete;
StackCanary_Impl& operator=(StackCanary_Impl&&) = delete;
~StackCanary_Impl() { ensure(); }
explicit operator bool() const volatile noexcept
{
for (std::size_t i = 0; i < n_bytes; ++i)
{
if (data_[i] != reference(i))
{
return false;
}
}
return true;
}
private:
void ensure() const volatile noexcept
{
if (!*this)
{
assert(false);
std::abort();
}
}
static constexpr std::uint8_t reference(const size_t i) noexcept { return (seed + (i * 0xC9U)) & 0xFFU; }
volatile std::uint8_t data_[n_bytes];
};
/// A simple utility class for debugging stack memory corruption.
/// The dtor will invoke assert(false) and std::abort() if memory corruption is detected.
/// The canary is designed to have a 1-byte alignment.
/// Generate reference values for searching in binary dumps:
///
/// >>> stage = lambda i: (0xC9 + (i * 0xC9)) & 0xFF
/// >>> bytes(map(stage, range(64))).hex()
template <std::size_t n_bytes = 64>
using StackCanary = volatile StackCanary_Impl<n_bytes>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment