parent
015a2ca208
commit
d926889559
|
@ -114,3 +114,7 @@
|
|||
2011-06-23 Cedric Bail
|
||||
|
||||
* Add Eina_LockRW.
|
||||
|
||||
2011-07-04 Carsten Haitzler (The Rasterman)
|
||||
|
||||
* Add eina_mmap safety handling.
|
||||
|
|
|
@ -57,7 +57,8 @@ eina_quadtree.h \
|
|||
eina_simple_xml_parser.h \
|
||||
eina_lock.h \
|
||||
eina_prefix.h \
|
||||
eina_refcount.h
|
||||
eina_refcount.h \
|
||||
eina_mmap.h
|
||||
|
||||
# Will be back for developper after 1.1.
|
||||
# eina_object.h
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef EINA_MMAP_H_
|
||||
#define EINA_MMAP_H_
|
||||
|
||||
/**
|
||||
* @addtogroup Eina_Mmap_Group Group
|
||||
*
|
||||
* @brief These functions provide helpers for safe mmap handling
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Enable or disable safe mmaped IO handling
|
||||
*
|
||||
* @param enabled The enabled state (to enable, pass EINA_TRUE)
|
||||
*
|
||||
* This enables (if possible on your platform) a signal handler for
|
||||
* SIGBUS, that replaces the "bad page" with a pzge of 0's (from /dev/zero)
|
||||
* if a SIGBUS occurs. This allows for safe mmap() of files that may truncate
|
||||
* or from files on devices with IO errors. Normally these cases will result
|
||||
* in a SIGBUS being delivered (and termination of yyour process), but
|
||||
* when "mmap safety" is enabled, this will not occur. Instead a page of
|
||||
* bytes of the value 0 will replace the "bad page", allowing the process
|
||||
* to continue and allow its own parsing error detection to safely abort
|
||||
* the operation without the process falling apart.
|
||||
*
|
||||
* If you disable mmap safety, the SIGBUS handler will be restored to its
|
||||
* default handler. Note that eina_file_map_all() and eina_file_map_new()
|
||||
* will automatically enable mmap safety as they provide an mmaped file IO
|
||||
* layer, and rely on mmap to not fail for any part of the file.
|
||||
*
|
||||
* If you set up your own SIGBUS handler, then this will effectively disable
|
||||
* the safe mmap handling and make you liable to crashes on IO to or from
|
||||
* such "damaged files" that would take down your process.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
EAPI Eina_Bool
|
||||
eina_mmap_safety_enabled_set(Eina_Bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Get the enabled state of mmap safety.
|
||||
*
|
||||
* @return The safety state (EINA_TRUE if enabled)
|
||||
*
|
||||
* This returns the mmap safety state set by eina_mmap_safety_enabled_set().
|
||||
* See eina_mmap_safety_enabled_set() for more information.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
EAPI Eina_Bool
|
||||
eina_mmap_safety_enabled_get(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
#endif
|
|
@ -31,6 +31,7 @@ eina_magic.c \
|
|||
eina_main.c \
|
||||
eina_matrixsparse.c \
|
||||
eina_mempool.c \
|
||||
eina_mmap.c \
|
||||
eina_module.c \
|
||||
eina_prefix.c \
|
||||
eina_quadtree.c \
|
||||
|
|
|
@ -65,6 +65,7 @@ void *alloca (size_t);
|
|||
#include "eina_hash.h"
|
||||
#include "eina_list.h"
|
||||
#include "eina_lock.h"
|
||||
#include "eina_mmap.h"
|
||||
|
||||
/*============================================================================*
|
||||
* Local *
|
||||
|
@ -867,6 +868,7 @@ eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
|
|||
if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
|
||||
#endif
|
||||
|
||||
eina_mmap_safety_enabled_set(EINA_TRUE);
|
||||
eina_lock_take(&file->lock);
|
||||
if (file->global_map == MAP_FAILED)
|
||||
file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
|
||||
|
@ -900,6 +902,7 @@ eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
|
|||
key[0] = offset;
|
||||
key[1] = length;
|
||||
|
||||
eina_mmap_safety_enabled_set(EINA_TRUE);
|
||||
eina_lock_take(&file->lock);
|
||||
|
||||
map = eina_hash_find(file->map, &key);
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/* EINA - EFL data type library
|
||||
* Copyright (C) 2011 Carsten Haitzler
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library;
|
||||
* if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
#elif defined __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
#elif defined _AIX
|
||||
# define alloca __alloca
|
||||
#elif defined _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
#else
|
||||
# ifndef HAVE_ALLOCA
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *alloca (size_t);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
#include <limits.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVIL
|
||||
# include <Evil.h>
|
||||
#endif
|
||||
|
||||
#include "eina_config.h"
|
||||
#include "eina_private.h"
|
||||
#include "eina_log.h"
|
||||
#include "eina_mmap.h"
|
||||
|
||||
/*============================================================================*
|
||||
* Local *
|
||||
*============================================================================*/
|
||||
static Eina_Bool mmap_safe = EINA_FALSE;
|
||||
#ifndef _WIN32
|
||||
static int _eina_mmap_log_dom = -1;
|
||||
static int _eina_mmap_zero_fd = -1;
|
||||
static long _eina_mmap_pagesize = -1;
|
||||
|
||||
#ifdef ERR
|
||||
#undef ERR
|
||||
#endif
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_eina_mmap_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef DBG
|
||||
#undef DBG
|
||||
#endif
|
||||
#define DBG(...) EINA_LOG_DOM_DBG(_eina_mmap_log_dom, __VA_ARGS__)
|
||||
|
||||
static void
|
||||
_eina_mmap_safe_sigbus(int sig __UNUSED__,
|
||||
siginfo_t *siginfo,
|
||||
void *ptr __UNUSED__)
|
||||
{
|
||||
unsigned char *addr = (unsigned char *)(siginfo->si_addr);
|
||||
int perrno;
|
||||
|
||||
/* save previous errno */
|
||||
perrno = errno;
|
||||
/* if problems was an unaligned access - complain accordingly and abort */
|
||||
if (siginfo->si_code == BUS_ADRALN)
|
||||
{
|
||||
ERR("Unaligned memory access. SIGBUS!!!");
|
||||
errno = perrno;
|
||||
abort();
|
||||
}
|
||||
/* send this to stderr - not eina_log. Specifically want this on stderr */
|
||||
fprintf(stderr,
|
||||
"EINA: Data at address 0x%lx is invalid. Replacing with zero page.\n",
|
||||
(unsigned long)addr);
|
||||
/* align address to the lower page boundary */
|
||||
addr = (unsigned char *)((long)addr & (~(_eina_mmap_pagesize - 1)));
|
||||
/* mmap a pzge of zero's from /dev/zero in there */
|
||||
if (mmap(addr, _eina_mmap_pagesize,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_PRIVATE | MAP_FIXED,
|
||||
_eina_mmap_zero_fd, 0) == MAP_FAILED)
|
||||
{
|
||||
/* mmap of /dev/zero failed :( */
|
||||
perror("mmap");
|
||||
ERR("Failed to mmap() /dev/zero in place of page. SIGBUS!!!");
|
||||
errno = perrno;
|
||||
abort();
|
||||
}
|
||||
/* restore previous errno */
|
||||
errno = perrno;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*============================================================================*
|
||||
* API *
|
||||
*============================================================================*/
|
||||
|
||||
EAPI Eina_Bool
|
||||
eina_mmap_safety_enabled_set(Eina_Bool enabled)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return EINA_FALSE;
|
||||
#else
|
||||
if (_eina_mmap_log_dom < 0)
|
||||
{
|
||||
_eina_mmap_log_dom = eina_log_domain_register("eina_mmap",
|
||||
EINA_LOG_COLOR_DEFAULT);
|
||||
if (_eina_mmap_log_dom < 0)
|
||||
{
|
||||
EINA_LOG_ERR("Could not register log domain: eina_mmap");
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
enabled = !!enabled;
|
||||
|
||||
if (mmap_safe == enabled) return mmap_safe;
|
||||
if (enabled)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
/* find out system page size the cleanest way we can */
|
||||
#ifdef _SC_PAGESIZE
|
||||
_eina_mmap_pagesize = sysconf(_SC_PAGESIZE);
|
||||
if (_eina_mmap_pagesize <= 0) return EINA_FALSE;
|
||||
#else
|
||||
_eina_mmap_pagesize = 4096;
|
||||
#endif
|
||||
/* no zero page device - open it */
|
||||
if (_eina_mmap_zero_fd < 0)
|
||||
{
|
||||
_eina_mmap_zero_fd = open("/dev/zero", O_RDWR);
|
||||
/* if we don;'t have one - fail to set up mmap safety */
|
||||
if (_eina_mmap_zero_fd < 0) return EINA_FALSE;
|
||||
}
|
||||
/* set up signal handler for SIGBUS */
|
||||
sa.sa_sigaction = _eina_mmap_safe_sigbus;
|
||||
sa.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGBUS, &sa, NULL) == 0) return EINA_FALSE;
|
||||
/* setup of SIGBUS handler failed, lets close zero page dev and fail */
|
||||
close(_eina_mmap_zero_fd);
|
||||
_eina_mmap_zero_fd = -1;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* reset signal handler to default for SIGBUS */
|
||||
signal(SIGBUS, SIG_DFL);
|
||||
}
|
||||
mmap_safe = enabled;
|
||||
return mmap_safe;
|
||||
#endif
|
||||
}
|
||||
|
||||
EAPI Eina_Bool
|
||||
eina_mmap_safety_enabled_get(void)
|
||||
{
|
||||
return mmap_safe;
|
||||
}
|
Loading…
Reference in New Issue