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
segv_handler(int sig)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
rk_test_mem_alloc(enum rk_test_mem_type type,const char * name,void * buf,size_t size)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
rk_test_mem_free(const char * map_name)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