libexplain
1.4.D001
|
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 : */