libexplain  1.4.D001
libexplain/is_efault/pointer.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2008-2011, 2013 Peter Miller
00004  * Written by Peter Miller <pmiller@opensource.org.au>
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 3 of the License, or (at
00009  * your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include <libexplain/ac/errno.h>
00021 #include <libexplain/ac/stdlib.h>
00022 #include <libexplain/ac/sys/mman.h>
00023 #include <libexplain/ac/unistd.h>
00024 
00025 #include <libexplain/is_efault.h>
00026 
00027 
00028 int
00029 explain_is_efault_pointer(const void *data, size_t data_size)
00030 {
00031 #ifdef HAVE_MINCORE
00032     /* mincore doesn't seem to work as expected on 64-bit Linux */
00033     static ssize_t  page_size;
00034     size_t          lo_pages;
00035     size_t          hi_pages;
00036     void            *lo;
00037     void            *hi;
00038     size_t          bsize;
00039     size_t          vec_bytes;
00040 
00041     /*
00042      * From the mincore(2) man page...
00043      *
00044      *     "The vec argument must point to an array containing at least
00045      *     (length+PAGE_SIZE-1) / PAGE_SIZE bytes.  On return, the least
00046      *     significant bit of each byte will be set if the corresponding
00047      *     page is currently resident in memory, and be clear otherwise.
00048      *     (The settings of the other bits in each byte are undefined;
00049      *     these bits are reserved for possible later use.)  Of course
00050      *     the information returned in vec is only a snapshot: pages that
00051      *     are not locked in memory can come and go at any moment, and
00052      *     the contents of vec may already be stale by the time this call
00053      *     returns."
00054      *
00055      * Of course, we don't give a damn whether the pages are in physical
00056      * memory or not, we are after the presence or absence of the ENOMEM
00057      * error, defined as
00058      *
00059      *    "ENOMEM: addr to addr + length contained unmapped memory."
00060      *
00061      * to tell us if the pointer points somewhere broken.
00062      */
00063     unsigned char   stack_vec[512];
00064 
00065     if (!data)
00066         return 1;
00067     if (!page_size)
00068     {
00069 #ifdef HAVE_GETPAGESIZE
00070         page_size = getpagesize();
00071 #else
00072         page_size = sysconf(_SC_PAGESIZE);
00073 #endif
00074     }
00075     if (page_size <= 0)
00076     {
00077         plan_b:
00078         return explain_is_efault_path(data);
00079     }
00080     lo_pages = (size_t)data / page_size;
00081     hi_pages = ((size_t)data + data_size + page_size - 1) / page_size;
00082     lo = (void *)(lo_pages * page_size);
00083     hi = (void *)(hi_pages * page_size);
00084     bsize = (char *)hi - (char *)lo;
00085     vec_bytes = hi_pages - lo_pages;
00086     if (vec_bytes > sizeof(stack_vec))
00087     {
00088         unsigned char   *heap_vec;
00089 
00090         /*
00091          * We can't hang on to the array and avoid the malloc next time,
00092          * because that wouldn't be thread safe.
00093          */
00094         heap_vec = malloc(vec_bytes);
00095         if (!heap_vec)
00096             goto plan_b;
00097         if (mincore(lo, bsize, (void *)heap_vec) < 0)
00098         {
00099             int             err;
00100 
00101             err = errno;
00102             free(heap_vec);
00103             if (err == ENOMEM)
00104                 return 1;
00105             goto plan_b;
00106         }
00107         free(heap_vec);
00108         return 0;
00109     }
00110 
00111     if (mincore(lo, bsize, (void *)stack_vec) < 0)
00112     {
00113         if (errno == ENOMEM)
00114             return 1;
00115         goto plan_b;
00116     }
00117     return 0;
00118 
00119 #else
00120     (void)data_size;
00121     if (!data)
00122         return 1;
00123     return explain_is_efault_path(data);
00124 #endif
00125 }
00126 
00127 
00128 /* vim: set ts=8 sw=4 et : */