1 /* EINA - EFL data type library
2 * Copyright (C) 2011 Carsten Haitzler
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
37 #include <sys/types.h>
52 #include "eina_config.h"
53 #include "eina_private.h"
55 #include "eina_mmap.h"
57 /*============================================================================*
59 *============================================================================*/
61 static Eina_Bool mmap_safe = EINA_FALSE;
64 static int _eina_mmap_log_dom = -1;
65 static int _eina_mmap_zero_fd = -1;
66 static long _eina_mmap_pagesize = -1;
71 #define ERR(...) EINA_LOG_DOM_ERR(_eina_mmap_log_dom, __VA_ARGS__)
76 #define DBG(...) EINA_LOG_DOM_DBG(_eina_mmap_log_dom, __VA_ARGS__)
79 _eina_mmap_safe_sigbus(int sig __UNUSED__,
83 unsigned char *addr = (unsigned char *)(siginfo->si_addr);
86 /* save previous errno */
88 /* if problems was an unaligned access - complain accordingly and abort */
89 if (siginfo->si_code == BUS_ADRALN)
91 ERR("Unaligned memory access. SIGBUS!!!");
95 /* send this to stderr - not eina_log. Specifically want this on stderr */
97 "EINA: Data at address 0x%lx is invalid. Replacing with zero page.\n",
99 /* align address to the lower page boundary */
100 addr = (unsigned char *)((long)addr & (~(_eina_mmap_pagesize - 1)));
101 /* mmap a pzge of zero's from /dev/zero in there */
102 if (mmap(addr, _eina_mmap_pagesize,
103 PROT_READ | PROT_WRITE | PROT_EXEC,
104 MAP_PRIVATE | MAP_FIXED,
105 _eina_mmap_zero_fd, 0) == MAP_FAILED)
107 /* mmap of /dev/zero failed :( */
109 ERR("Failed to mmap() /dev/zero in place of page. SIGBUS!!!");
113 /* Look into mmaped Eina_File if it was one of them, just to remember for later request */
114 eina_file_mmap_faulty(addr, _eina_mmap_pagesize);
115 /* restore previous errno */
120 /*============================================================================*
122 *============================================================================*/
125 eina_mmap_safety_enabled_set(Eina_Bool enabled)
127 #ifndef HAVE_SIGINFO_T
131 if (_eina_mmap_log_dom < 0)
133 _eina_mmap_log_dom = eina_log_domain_register("eina_mmap",
134 EINA_LOG_COLOR_DEFAULT);
135 if (_eina_mmap_log_dom < 0)
137 EINA_LOG_ERR("Could not register log domain: eina_mmap");
144 if (mmap_safe == enabled) return mmap_safe;
149 /* find out system page size the cleanest way we can */
151 _eina_mmap_pagesize = sysconf(_SC_PAGESIZE);
152 if (_eina_mmap_pagesize <= 0) return EINA_FALSE;
154 _eina_mmap_pagesize = 4096;
156 /* no zero page device - open it */
157 if (_eina_mmap_zero_fd < 0)
159 _eina_mmap_zero_fd = open("/dev/zero", O_RDWR);
160 /* if we don;'t have one - fail to set up mmap safety */
161 if (_eina_mmap_zero_fd < 0) return EINA_FALSE;
163 /* set up signal handler for SIGBUS */
164 sa.sa_sigaction = _eina_mmap_safe_sigbus;
165 sa.sa_flags = SA_RESTART | SA_SIGINFO;
166 sigemptyset(&sa.sa_mask);
167 /* FIXME: This is rubbish. We return EINA_FALSE whether sigaction
168 * fails or not. And we never set mmap_safe, so we always hit this
170 if (sigaction(SIGBUS, &sa, NULL) == 0) return EINA_FALSE;
171 /* setup of SIGBUS handler failed, lets close zero page dev and fail */
172 close(_eina_mmap_zero_fd);
173 _eina_mmap_zero_fd = -1;
178 /* reset signal handler to default for SIGBUS */
179 signal(SIGBUS, SIG_DFL);
187 eina_mmap_safety_enabled_get(void)