>From e7ec75f623c07718c4caf2b157d6763ff14d63f2 Mon Sep 17 00:00:00 2001 From: Jason Evans Date: Fri, 4 Jun 2010 12:55:46 -0700 Subject: [PATCH] Modify mincore(2)-based validate_mem() checks. Verify that if mincore(2) claims a word is unmapped, msync(2) agrees. Also check for EAGAIN errors from mincore(2), as required on Linux. Fix both mincore(2) and msync(2) calls to properly handle unaligned words that straddle page boundaries. --- src/x86/Ginit.c | 32 +++++++++++++++++++++++++++++--- src/x86_64/Ginit.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/x86/Ginit.c b/src/x86/Ginit.c index 0af616a..f4189e7 100644 --- a/src/x86/Ginit.c +++ b/src/x86/Ginit.c @@ -30,6 +30,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include +#include +#ifdef HAVE_MINCORE +#include +#endif #include "unwind_i.h" @@ -90,6 +94,12 @@ validate_mem (unw_word_t addr) #ifdef HAVE_MINCORE char mvec[2]; /* Unaligned access may cross page boundary */ #endif + size_t len; + + if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr)) + len = PAGE_SIZE; + else + len = PAGE_SIZE * 2; addr = PAGE_START(addr); @@ -103,11 +113,27 @@ validate_mem (unw_word_t addr) } #ifdef HAVE_MINCORE - if (mincore ((void *) addr, sizeof (unw_word_t), mvec) == -1) + while (1) + { + if (mincore ((void *) addr, len, mvec) == 0) + break; + switch (errno) + { + case EAGAIN: break; + case ENOMEM: + /* mincore() doesn't always agree with msync() on Linux, so make + sure that msync() also thinks addr is not mapped. */ + if (msync ((void *) addr, len, MS_ASYNC) != -1) + goto MINCORE_OUT; + return -1; + case EFAULT: case EINVAL: default: abort (); + } + } +MINCORE_OUT: #else - if (msync ((void *) addr, sizeof (unw_word_t), MS_ASYNC) == -1) -#endif + if (msync ((void *) addr, len, MS_ASYNC) == -1) return -1; +#endif victim = lga_victim; for (i = 0; i < NLGA; i++) { diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c index 14614f1..babb002 100644 --- a/src/x86_64/Ginit.c +++ b/src/x86_64/Ginit.c @@ -33,6 +33,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include +#ifdef HAVE_MINCORE +#include +#endif #include "unwind_i.h" @@ -93,6 +96,12 @@ validate_mem (unw_word_t addr) #ifdef HAVE_MINCORE char mvec[2]; /* Unaligned access may cross page boundary */ #endif + size_t len; + + if (PAGE_START(addr + sizeof (unw_word_t) - 1) == PAGE_START(addr)) + len = PAGE_SIZE; + else + len = PAGE_SIZE * 2; addr = PAGE_START(addr); @@ -106,11 +115,27 @@ validate_mem (unw_word_t addr) } #ifdef HAVE_MINCORE - if (mincore ((void *) addr, sizeof (unw_word_t), mvec) == -1) + while (1) + { + if (mincore ((void *) addr, len, mvec) == 0) + break; + switch (errno) + { + case EAGAIN: break; + case ENOMEM: + /* mincore() doesn't always agree with msync() on Linux, so make + sure that msync() also thinks addr is not mapped. */ + if (msync ((void *) addr, len, MS_ASYNC) != -1) + goto MINCORE_OUT; + return -1; + case EFAULT: case EINVAL: default: abort (); + } + } +MINCORE_OUT: #else - if (msync ((void *) addr, sizeof (unw_word_t), MS_ASYNC) == -1) -#endif + if (msync ((void *) addr, len, MS_ASYNC) == -1) return -1; +#endif victim = lga_victim; for (i = 0; i < NLGA; i++) { -- 1.6.6