28#define _RWSTD_TEST_SRC
49# include <sys/types.h>
55# define GETPAGESIZE() getpagesize ()
57# define GETPAGESIZE() sysconf (_SC_PAGESIZE)
60# define GETPAGESIZE() sysconf (_SC_PAGE_SIZE)
70# include <sys/types.h>
73# define GETPAGESIZE() getpagesize ()
80 static long pagesize_ = 0;
84 GetSystemInfo (&info);
85 pagesize_ = long (info.dwPageSize);
95 PROT_RDWR = PROT_READ | PROT_WRITE,
100#define MAP_ANONYMOUS 0
102#define MAP_FAILED ((CaddrT)-1)
112 PAGE_EXECUTE_READWRITE,
113 PAGE_EXECUTE_READWRITE
118_rw_translate_prot (
int prot)
120 if (0 <= prot && prot <
sizeof _rw_prots /
sizeof *_rw_prots)
121 return _rw_prots[prot];
123 return PAGE_NOACCESS;
130 addr = VirtualAlloc (
addr,
len, MEM_RESERVE | MEM_COMMIT,
131 _rw_translate_prot (prot));
144 if (VirtualFree (
addr, 0, MEM_RELEASE))
156 if (VirtualProtect (
addr,
len, _rw_translate_prot (prot), &flOldProt))
166# define MAP_PRIVATE 0
171# define MAP_ANONYMOUS 0
205static Blocks* _rw_head = 0;
206static Blocks* _rw_tail = 0;
214static Pair* _rw_table = 0;
215static size_t _rw_table_size = 0;
216static size_t _rw_table_max_size = 0;
226 const size_t half =
dist >> 1;
262 RW_ASSERT (0 == ((pagemask + 1) & pagemask));
265 const size_t off = size_t (
addr) & pagemask;
272 const int res = mprotect (caddr_,
size, PROT_READ | PROT_WRITE);
274 "mprotect failed: errno = %{#m} (%{m})");
278 const int res = mprotect (caddr_, size_, PROT_READ);
280 "mprotect failed: errno = %{#m} (%{m})");
299 const int res = munmap (caddr, _rw_table_size);
301 "munmap(%#p, %zu) failed: errno = %{#m} (%{m})",
302 _rw_table, _rw_table_size);
306 _rw_table_max_size = 0;
317 if (_rw_table_max_size == _rw_stats.
blocks_) {
321 const size_t new_size = _rw_table_size + pagesize;
323 const CaddrT caddr = mmap (0, new_size,
324 PROT_READ | PROT_WRITE,
332 memcpy (caddr, _rw_table, _rw_stats.
blocks_ * sizeof (
Pair));
335 const int res = mprotect (caddr, new_size, PROT_READ);
337 "mprotect(%#p, %zu, PROT_READ) failed: errno = %{#m} (%{m})",
344 _rw_table_size = new_size;
345 _rw_table_max_size = new_size /
sizeof (
Pair);
357 Pair*
const begin = _rw_table;
359 Pair*
const it = _rw_lower_bound (begin, end,
info.data_);
365 memmove (it + 1, it, (end - it) *
sizeof (
Pair));
380_rw_table_remove (
Pair* it)
382 const size_t index = size_t (it - _rw_table);
385 "invalid index in _rw_table_remove: %zu",
index);
395_rw_allocate_blocks ()
398 static size_t blocks_per_page = 0;
402 if (0 == blocks_per_page)
403 blocks_per_page = (pagesize -
sizeof (
Blocks)) /
sizeof (
BlockInfo) + 1;
405 const CaddrT caddr = mmap (0, pagesize,
406 PROT_READ | PROT_WRITE,
411 memset (caddr, 0, pagesize);
418 const int res = mprotect (caddr, pagesize, PROT_READ);
420 "mprotect(%#p, %zu, PROT_READ) failed: errno = %{#m} (%{m})",
427 _rw_tail->
next_ = blocks;
446 "_rw_free_blocks called when %zu blocks are not freed",
454 _rw_head = _rw_head->
next_;
456 const int res = munmap (caddr, pagesize);
459 "munmap(%#p, %zu) failed: errno = %{#m} (%{m})",
468_rw_find_unused_from (
Blocks* it)
492 if (!
res && _rw_allocate_blocks ()) {
498 "logic error in _rw_find_unused: res == 0 after "
499 "_rw_allocate_blocks() succeeded ");
509_rw_find_by_addr (
void*
addr)
512 return _rw_binary_search (_rw_table, end,
addr);
517_rw_get_prot (
int flags)
527 const char*
const envvar = getenv (
"RWSTD_ALLOC_FLAGS");
529 return atoi (envvar);
539 static const int RWSTD_ALLOC_FLAGS = _rw_getenvflags ();
542 if (-1 ==
flags && 0 != RWSTD_ALLOC_FLAGS)
543 flags = RWSTD_ALLOC_FLAGS;
546 if (!_rw_table_grow ())
549 if (
BlockInfo *info = _rw_find_unused ()) {
553 newinfo.
udsz_ = nbytes;
558 newinfo.
addr_ = malloc (nbytes);
561 newinfo.
size_ = nbytes;
568 size_t size = nbytes + pagesize;
571 RW_ASSERT (0 == (pagesize & (pagesize - 1)));
590 guard +=
size - pagesize;
593 int res = mprotect (guard, pagesize, PROT_NONE);
595 "mprotect failed: errno = %{#m} (%{m})");
609 _rw_table_insert (*info);
623 if (
Pair *it = _rw_find_by_addr (
addr)) {
627 if (-1 == info.flags_)
632 const int res = munmap (caddr, info.size_);
634 "munmap(%#p, %zu) failed: errno = %{#m} (%{m})",
643 _rw_table_remove (it);
652 "rw_free(%#p): the address is not a valid address, "
653 "returned by rw_alloc()",
#define _RWSTD_REINTERPRET_CAST(T, x)
#define _RWSTD_STATIC_CAST(T, x)
_TEST_EXPORT void rw_free(void *addr)
_TEST_EXPORT void * rw_alloc(size_t nbytes, int flags)
_RWSTD_MUNMAP_ARG1_T CaddrT
MemRWGuard(void *addr, size_t size)
std::ostream & info() noexcept
replacement for std::cout for NeBuild logging.
_TEST_EXPORT int rw_fatal(int expr, const char *filename, int line, const char *fmtspec,...)
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)