1 /* $NetBSD: test-mem.c,v 1.2 2017/01/28 21:31:50 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1999 - 2004 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <config.h> 37 38 #ifdef HAVE_SYS_MMAN_H 39 #include <sys/mman.h> 40 #endif 41 #include <stdio.h> 42 #include <string.h> 43 #include <err.h> 44 #include <krb5/roken.h> 45 46 #include "test-mem.h" 47 48 /* #undef HAVE_MMAP */ 49 50 struct { 51 void *start; 52 size_t size; 53 void *data_start; 54 size_t data_size; 55 enum rk_test_mem_type type; 56 int fd; 57 } map; 58 59 #ifdef HAVE_SIGACTION 60 61 struct sigaction sa, osa; 62 63 #else 64 65 void (* osigh)(int); 66 67 #endif 68 69 char *testname; 70 71 static RETSIGTYPE 72 segv_handler(int sig) 73 { 74 int fd; 75 ssize_t ret; 76 char msg[] = "SIGSEGV i current test: "; 77 78 fd = open("/dev/stdout", O_WRONLY, 0600); 79 if (fd >= 0) { 80 ret = write(fd, msg, sizeof(msg) - 1); 81 if (ret != -1) 82 ret = write(fd, testname, strlen(testname)); 83 if (ret != -1) 84 ret = write(fd, "\n", 1); 85 close(fd); 86 } 87 _exit(1); 88 } 89 90 #define TESTREC() \ 91 if (testname) \ 92 errx(1, "test %s run recursively on %s", name, testname); \ 93 testname = strdup(name); \ 94 if (testname == NULL) \ 95 errx(1, "malloc"); 96 97 98 ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL 99 rk_test_mem_alloc(enum rk_test_mem_type type, const char *name, 100 void *buf, size_t size) 101 { 102 #ifndef HAVE_MMAP 103 unsigned char *p; 104 105 TESTREC(); 106 107 p = malloc(size + 2); 108 if (p == NULL) 109 errx(1, "malloc"); 110 map.type = type; 111 map.start = p; 112 map.size = size + 2; 113 p[0] = 0xff; 114 p[map.size-1] = 0xff; 115 map.data_start = p + 1; 116 #else 117 unsigned char *p; 118 int flags, ret, fd; 119 size_t pagesize = getpagesize(); 120 121 TESTREC(); 122 123 map.type = type; 124 125 #ifdef MAP_ANON 126 flags = MAP_ANON; 127 fd = -1; 128 #else 129 flags = 0; 130 fd = open ("/dev/zero", O_RDONLY); 131 if(fd < 0) 132 err (1, "open /dev/zero"); 133 #endif 134 map.fd = fd; 135 flags |= MAP_PRIVATE; 136 137 map.size = size + pagesize - (size % pagesize) + pagesize * 2; 138 139 p = (unsigned char *)mmap(0, map.size, PROT_READ | PROT_WRITE, 140 flags, fd, 0); 141 if (p == (unsigned char *)MAP_FAILED) 142 err (1, "mmap"); 143 144 map.start = p; 145 146 ret = mprotect ((void *)p, pagesize, 0); 147 if (ret < 0) 148 err (1, "mprotect"); 149 150 ret = mprotect (p + map.size - pagesize, pagesize, 0); 151 if (ret < 0) 152 err (1, "mprotect"); 153 154 switch (type) { 155 case RK_TM_OVERRUN: 156 map.data_start = p + map.size - pagesize - size; 157 break; 158 case RK_TM_UNDERRUN: 159 map.data_start = p + pagesize; 160 break; 161 default: 162 abort(); 163 } 164 #endif 165 #ifdef HAVE_SIGACTION 166 sigemptyset (&sa.sa_mask); 167 sa.sa_flags = 0; 168 #ifdef SA_RESETHAND 169 sa.sa_flags |= SA_RESETHAND; 170 #endif 171 sa.sa_handler = segv_handler; 172 sigaction (SIGSEGV, &sa, &osa); 173 #else 174 osigh = signal(SIGSEGV, segv_handler); 175 #endif 176 177 map.data_size = size; 178 if (buf) 179 memcpy(map.data_start, buf, size); 180 return map.data_start; 181 } 182 183 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 184 rk_test_mem_free(const char *map_name) 185 { 186 #ifndef HAVE_MMAP 187 unsigned char *p = map.start; 188 189 if (testname == NULL) 190 errx(1, "test_mem_free call on no free"); 191 192 if (p[0] != 0xff) 193 errx(1, "%s: %s underrun %x\n", testname, map_name, p[0]); 194 if (p[map.size-1] != 0xff) 195 errx(1, "%s: %s overrun %x\n", testname, map_name, p[map.size - 1]); 196 free(map.start); 197 #else 198 int ret; 199 200 if (testname == NULL) 201 errx(1, "test_mem_free call on no free"); 202 203 ret = munmap (map.start, map.size); 204 if (ret < 0) 205 err (1, "munmap"); 206 if (map.fd > 0) 207 close(map.fd); 208 #endif 209 free(testname); 210 testname = NULL; 211 212 #ifdef HAVE_SIGACTION 213 sigaction (SIGSEGV, &osa, NULL); 214 #else 215 signal (SIGSEGV, osigh); 216 #endif 217 } 218