From 6fdae129967de80fd5a27d5c3edaf9039fd29d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B5=D0=BE=D0=BD=D0=B8=D0=B4=20=D0=AE=D1=80=D1=8C?= =?UTF-8?q?=D0=B5=D0=B2=20=28Leonid=20Yuriev=29?= Date: Fri, 14 Oct 2022 00:20:37 +0300 Subject: [PATCH] mdbx: workaround for `mremap()` defect (backport). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Есть основание полагать, что mremap() может возвращать MAP_FAILED, но НЕ устанавливать errno в некоторых пограничных ситуациях. Например, когда системных ресурсов не хватает на актуализацию/копирование/клонирование состояния отображения на финальной стадии, в том числе из-за раскраски исходного отображения разными флагами через madvise(). --- ChangeLog.md | 1 + src/osal.c | 39 +++++++++++++++++++++++++++++++-------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ca3989ba..68be0f7d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,7 @@ Fixes: - Fixed builds with older libc versions after using `fcntl64()` (backport). - Fixed builds with older `stdatomic.h` versions, where the `ATOMIC_*_LOCK_FREE` macros mistakenly redefined using functions (backport). + - Added workaround for `mremap()` defect to avoid assertion failure (backport). ## v0.11.12 (Эребуни) at 2022-10-12 diff --git a/src/osal.c b/src/osal.c index f5838653..04d97626 100644 --- a/src/osal.c +++ b/src/osal.c @@ -1547,6 +1547,7 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map, map->limit = 0; map->current = 0; map->address = nullptr; + assert(errno != 0); return errno; } map->limit = limit; @@ -1585,8 +1586,10 @@ MDBX_INTERNAL_FUNC int mdbx_munmap(mdbx_mmap_t *map) { if (!NT_SUCCESS(rc)) ntstatus2errcode(rc); #else - if (unlikely(munmap(map->address, map->limit))) + if (unlikely(munmap(map->address, map->limit))) { + assert(errno != 0); return errno; + } #endif /* ! Windows */ map->limit = 0; @@ -1809,8 +1812,10 @@ retry_mapview:; if (limit < map->limit) { /* unmap an excess at end of mapping. */ // coverity[offset_free : FALSE] - if (unlikely(munmap(map->dxb + limit, map->limit - limit))) + if (unlikely(munmap(map->dxb + limit, map->limit - limit))) { + assert(errno != 0); return errno; + } map->limit = limit; return rc; } @@ -1822,14 +1827,19 @@ retry_mapview:; assert(limit > map->limit); uint8_t *ptr = MAP_FAILED; -#if defined(MREMAP_MAYMOVE) +#if (defined(__linux__) || defined(__gnu_linux__)) && defined(_GNU_SOURCE) ptr = mremap(map->address, map->limit, limit, - (flags & MDBX_MRESIZE_MAY_MOVE) ? MREMAP_MAYMOVE : 0); +#if defined(MREMAP_MAYMOVE) + (flags & MDBX_MRESIZE_MAY_MOVE) ? MREMAP_MAYMOVE : +#endif /* MREMAP_MAYMOVE */ + 0); if (ptr == MAP_FAILED) { err = errno; + assert(err != 0); switch (err) { default: return err; + case 0 /* paranoia */: case EAGAIN: case ENOMEM: return MDBX_UNABLE_EXTEND_MAPSIZE; @@ -1837,7 +1847,7 @@ retry_mapview:; break; } } -#endif /* MREMAP_MAYMOVE */ +#endif /* Linux & _GNU_SOURCE */ const unsigned mmap_flags = MAP_CONCEAL | MAP_SHARED | MAP_FILE | MAP_NORESERVE | @@ -1850,17 +1860,22 @@ retry_mapview:; ptr = mmap(map->dxb + map->limit, limit - map->limit, mmap_prot, mmap_flags | MAP_FIXED_NOREPLACE, map->fd, map->limit); if (ptr == map->dxb + map->limit) + /* успешно прилепили отображение в конец */ ptr = map->dxb; else if (ptr != MAP_FAILED) { /* the desired address is busy, unmap unsuitable one */ - if (unlikely(munmap(ptr, limit - map->limit))) + if (unlikely(munmap(ptr, limit - map->limit))) { + assert(errno != 0); return errno; + } ptr = MAP_FAILED; } else { err = errno; + assert(err != 0); switch (err) { default: return err; + case 0 /* paranoia */: case EAGAIN: case ENOMEM: return MDBX_UNABLE_EXTEND_MAPSIZE; @@ -1879,8 +1894,10 @@ retry_mapview:; return MDBX_UNABLE_EXTEND_MAPSIZE; } - if (unlikely(munmap(map->address, map->limit))) + if (unlikely(munmap(map->address, map->limit))) { + assert(errno != 0); return errno; + } // coverity[pass_freed_arg : FALSE] ptr = mmap(map->address, limit, mmap_prot, @@ -1924,6 +1941,7 @@ retry_mapview:; map->limit = 0; map->current = 0; map->address = nullptr; + assert(errno != 0); return errno; } rc = MDBX_UNABLE_EXTEND_MAPSIZE; @@ -1950,8 +1968,10 @@ retry_mapview:; #if MDBX_ENABLE_MADVISE #ifdef MADV_DONTFORK - if (unlikely(madvise(map->address, map->limit, MADV_DONTFORK) != 0)) + if (unlikely(madvise(map->address, map->limit, MADV_DONTFORK) != 0)) { + assert(errno != 0); return errno; + } #endif /* MADV_DONTFORK */ #ifdef MADV_NOHUGEPAGE (void)madvise(map->address, map->limit, MADV_NOHUGEPAGE); @@ -1960,6 +1980,9 @@ retry_mapview:; #endif /* POSIX / Windows */ + assert(rc != MDBX_SUCCESS || + (map->address != nullptr && map->address != MAP_FAILED && + map->current == size && map->limit == limit)); return rc; }