Date: Fri, 25 Jul 2025 14:08:02 +0100
On Fri, Jul 25, 2025 at 1:19 PM Frederick Virchanza Gotham wrote:
> struct badptr_t {
> alignas(PAGE_SIZE) inline static char unsigned const
> dummy[PAGE_SIZE] = {};
>
> template<typename T>
> operator T*(void) const
> {
> return static_cast<T*>( const_cast<void*>(
> static_cast<void const*>( dummy + PAGE_SIZE / 2u ) ) );
> }
> };
We can get it to segfault upon reading by setting the page permission to "none".
Check out the following GodBolt, and then try comment out Line #12
where it says "mprotect".
https://godbolt.org/z/9MGas1xPe
And here it is copy-pasted:
#include <cstdlib> // abort, aligned_alloc
#include <sys/mman.h> // mprotect
#include <unistd.h> // getpagesize
struct badptr_t {
inline static int page_size = 0;
static char *Init(void) noexcept
{
page_size = ::getpagesize();
char *p = (char*)std::aligned_alloc(page_size,page_size);
if ( nullptr == p ) std::abort();
::mprotect(p,page_size,PROT_NONE);
return p;
}
inline static char *const p_bad_page = Init();
template<typename T>
operator T*(void) const
{
return static_cast<T*>( static_cast<void*>( p_bad_page +
page_size / 2 ) );
}
};
constexpr badptr_t badptr{};
#include <iostream>
int main(void)
{
std::cout << "First line in main\n";
char *p = badptr;
std::cout << p << std::endl;
std::cout << "Last line in main\n";
}
Even though this works . . . i.e. we get a segfault . . . it would be
nicer to have the compiler's cooperation so that when NDEBUG is
undefined, it gives a good explanatory message saying that 'badptr'
was dereferenced.
> struct badptr_t {
> alignas(PAGE_SIZE) inline static char unsigned const
> dummy[PAGE_SIZE] = {};
>
> template<typename T>
> operator T*(void) const
> {
> return static_cast<T*>( const_cast<void*>(
> static_cast<void const*>( dummy + PAGE_SIZE / 2u ) ) );
> }
> };
We can get it to segfault upon reading by setting the page permission to "none".
Check out the following GodBolt, and then try comment out Line #12
where it says "mprotect".
https://godbolt.org/z/9MGas1xPe
And here it is copy-pasted:
#include <cstdlib> // abort, aligned_alloc
#include <sys/mman.h> // mprotect
#include <unistd.h> // getpagesize
struct badptr_t {
inline static int page_size = 0;
static char *Init(void) noexcept
{
page_size = ::getpagesize();
char *p = (char*)std::aligned_alloc(page_size,page_size);
if ( nullptr == p ) std::abort();
::mprotect(p,page_size,PROT_NONE);
return p;
}
inline static char *const p_bad_page = Init();
template<typename T>
operator T*(void) const
{
return static_cast<T*>( static_cast<void*>( p_bad_page +
page_size / 2 ) );
}
};
constexpr badptr_t badptr{};
#include <iostream>
int main(void)
{
std::cout << "First line in main\n";
char *p = badptr;
std::cout << p << std::endl;
std::cout << "Last line in main\n";
}
Even though this works . . . i.e. we get a segfault . . . it would be
nicer to have the compiler's cooperation so that when NDEBUG is
undefined, it gives a good explanatory message saying that 'badptr'
was dereferenced.
Received on 2025-07-25 13:08:19