1/*	$NetBSD$	*/
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
50struct {
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
61struct sigaction sa, osa;
62
63#else
64
65void (* osigh)(int);
66
67#endif
68
69char *testname;
70
71static RETSIGTYPE
72segv_handler(int sig)
73{
74    int fd;
75    char msg[] = "SIGSEGV i current test: ";
76
77    fd = open("/dev/stdout", O_WRONLY, 0600);
78    if (fd >= 0) {
79	(void)write(fd, msg, sizeof(msg) - 1);
80	(void)write(fd, testname, strlen(testname));
81	(void)write(fd, "\n", 1);
82	close(fd);
83    }
84    _exit(1);
85}
86
87#define TESTREC()							\
88    if (testname)							\
89	errx(1, "test %s run recursively on %s", name, testname);	\
90    testname = strdup(name);						\
91    if (testname == NULL)						\
92	errx(1, "malloc");
93
94
95ROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
96rk_test_mem_alloc(enum rk_test_mem_type type, const char *name,
97		  void *buf, size_t size)
98{
99#ifndef HAVE_MMAP
100    unsigned char *p;
101
102    TESTREC();
103
104    p = malloc(size + 2);
105    if (p == NULL)
106	errx(1, "malloc");
107    map.type = type;
108    map.start = p;
109    map.size = size + 2;
110    p[0] = 0xff;
111    p[map.size-1] = 0xff;
112    map.data_start = p + 1;
113#else
114    unsigned char *p;
115    int flags, ret, fd;
116    size_t pagesize = getpagesize();
117
118    TESTREC();
119
120    map.type = type;
121
122#ifdef MAP_ANON
123    flags = MAP_ANON;
124    fd = -1;
125#else
126    flags = 0;
127    fd = open ("/dev/zero", O_RDONLY);
128    if(fd < 0)
129	err (1, "open /dev/zero");
130#endif
131    map.fd = fd;
132    flags |= MAP_PRIVATE;
133
134    map.size = size + pagesize - (size % pagesize) + pagesize * 2;
135
136    p = (unsigned char *)mmap(0, map.size, PROT_READ | PROT_WRITE,
137			      flags, fd, 0);
138    if (p == (unsigned char *)MAP_FAILED)
139	err (1, "mmap");
140
141    map.start = p;
142
143    ret = mprotect ((void *)p, pagesize, 0);
144    if (ret < 0)
145	err (1, "mprotect");
146
147    ret = mprotect (p + map.size - pagesize, pagesize, 0);
148    if (ret < 0)
149	err (1, "mprotect");
150
151    switch (type) {
152    case RK_TM_OVERRUN:
153	map.data_start = p + map.size - pagesize - size;
154	break;
155    case RK_TM_UNDERRUN:
156	map.data_start = p + pagesize;
157	break;
158    default:
159	abort();
160    }
161#endif
162#ifdef HAVE_SIGACTION
163    sigemptyset (&sa.sa_mask);
164    sa.sa_flags = 0;
165#ifdef SA_RESETHAND
166    sa.sa_flags |= SA_RESETHAND;
167#endif
168    sa.sa_handler = segv_handler;
169    sigaction (SIGSEGV, &sa, &osa);
170#else
171    osigh = signal(SIGSEGV, segv_handler);
172#endif
173
174    map.data_size = size;
175    if (buf)
176	memcpy(map.data_start, buf, size);
177    return map.data_start;
178}
179
180ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
181rk_test_mem_free(const char *map_name)
182{
183#ifndef HAVE_MMAP
184    unsigned char *p = map.start;
185
186    if (testname == NULL)
187	errx(1, "test_mem_free call on no free");
188
189    if (p[0] != 0xff)
190	errx(1, "%s: %s underrun %x\n", testname, map_name, p[0]);
191    if (p[map.size-1] != 0xff)
192	errx(1, "%s: %s overrun %x\n", testname, map_name, p[map.size - 1]);
193    free(map.start);
194#else
195    int ret;
196
197    if (testname == NULL)
198	errx(1, "test_mem_free call on no free");
199
200    ret = munmap (map.start, map.size);
201    if (ret < 0)
202	err (1, "munmap");
203    if (map.fd > 0)
204	close(map.fd);
205#endif
206    free(testname);
207    testname = NULL;
208
209#ifdef HAVE_SIGACTION
210    sigaction (SIGSEGV, &osa, NULL);
211#else
212    signal (SIGSEGV, osigh);
213#endif
214}
215