Skip to content

Instantly share code, notes, and snippets.

@pavel-kirienko
Created May 26, 2025 19:56
Show Gist options
  • Select an option

  • Save pavel-kirienko/f04058defcb21a9f20391e2faa5681d5 to your computer and use it in GitHub Desktop.

Select an option

Save pavel-kirienko/f04058defcb21a9f20391e2faa5681d5 to your computer and use it in GitHub Desktop.

Revisions

  1. pavel-kirienko created this gist May 26, 2025.
    66 changes: 66 additions & 0 deletions stack_canary.hpp
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,66 @@
    #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>;

    }