1178825Sdfr/*
2233294Sstas * Copyright (c) 1999 - 2004 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include <config.h>
35233294Sstas
36178825Sdfr#ifdef HAVE_SYS_MMAN_H
37178825Sdfr#include <sys/mman.h>
38178825Sdfr#endif
39178825Sdfr#include <stdio.h>
40178825Sdfr#include <string.h>
41178825Sdfr#include <err.h>
42178825Sdfr#include "roken.h"
43178825Sdfr
44178825Sdfr#include "test-mem.h"
45178825Sdfr
46178825Sdfr/* #undef HAVE_MMAP */
47178825Sdfr
48178825Sdfrstruct {
49178825Sdfr    void *start;
50178825Sdfr    size_t size;
51178825Sdfr    void *data_start;
52178825Sdfr    size_t data_size;
53178825Sdfr    enum rk_test_mem_type type;
54178825Sdfr    int fd;
55178825Sdfr} map;
56178825Sdfr
57233294Sstas#ifdef HAVE_SIGACTION
58233294Sstas
59178825Sdfrstruct sigaction sa, osa;
60178825Sdfr
61233294Sstas#else
62233294Sstas
63233294Sstasvoid (* osigh)(int);
64233294Sstas
65233294Sstas#endif
66233294Sstas
67178825Sdfrchar *testname;
68178825Sdfr
69178825Sdfrstatic RETSIGTYPE
70178825Sdfrsegv_handler(int sig)
71178825Sdfr{
72178825Sdfr    int fd;
73178825Sdfr    char msg[] = "SIGSEGV i current test: ";
74233294Sstas
75178825Sdfr    fd = open("/dev/stdout", O_WRONLY, 0600);
76178825Sdfr    if (fd >= 0) {
77233294Sstas	(void)write(fd, msg, sizeof(msg) - 1);
78233294Sstas	(void)write(fd, testname, strlen(testname));
79233294Sstas	(void)write(fd, "\n", 1);
80178825Sdfr	close(fd);
81178825Sdfr    }
82178825Sdfr    _exit(1);
83178825Sdfr}
84178825Sdfr
85178825Sdfr#define TESTREC()							\
86178825Sdfr    if (testname)							\
87178825Sdfr	errx(1, "test %s run recursively on %s", name, testname);	\
88178825Sdfr    testname = strdup(name);						\
89178825Sdfr    if (testname == NULL)						\
90178825Sdfr	errx(1, "malloc");
91178825Sdfr
92178825Sdfr
93233294SstasROKEN_LIB_FUNCTION void * ROKEN_LIB_CALL
94178825Sdfrrk_test_mem_alloc(enum rk_test_mem_type type, const char *name,
95178825Sdfr		  void *buf, size_t size)
96178825Sdfr{
97178825Sdfr#ifndef HAVE_MMAP
98178825Sdfr    unsigned char *p;
99233294Sstas
100178825Sdfr    TESTREC();
101178825Sdfr
102178825Sdfr    p = malloc(size + 2);
103178825Sdfr    if (p == NULL)
104178825Sdfr	errx(1, "malloc");
105178825Sdfr    map.type = type;
106178825Sdfr    map.start = p;
107178825Sdfr    map.size = size + 2;
108178825Sdfr    p[0] = 0xff;
109233294Sstas    p[map.size-1] = 0xff;
110178825Sdfr    map.data_start = p + 1;
111178825Sdfr#else
112178825Sdfr    unsigned char *p;
113178825Sdfr    int flags, ret, fd;
114178825Sdfr    size_t pagesize = getpagesize();
115178825Sdfr
116178825Sdfr    TESTREC();
117178825Sdfr
118178825Sdfr    map.type = type;
119178825Sdfr
120178825Sdfr#ifdef MAP_ANON
121178825Sdfr    flags = MAP_ANON;
122178825Sdfr    fd = -1;
123178825Sdfr#else
124178825Sdfr    flags = 0;
125178825Sdfr    fd = open ("/dev/zero", O_RDONLY);
126178825Sdfr    if(fd < 0)
127178825Sdfr	err (1, "open /dev/zero");
128178825Sdfr#endif
129178825Sdfr    map.fd = fd;
130178825Sdfr    flags |= MAP_PRIVATE;
131178825Sdfr
132178825Sdfr    map.size = size + pagesize - (size % pagesize) + pagesize * 2;
133178825Sdfr
134178825Sdfr    p = (unsigned char *)mmap(0, map.size, PROT_READ | PROT_WRITE,
135178825Sdfr			      flags, fd, 0);
136178825Sdfr    if (p == (unsigned char *)MAP_FAILED)
137178825Sdfr	err (1, "mmap");
138178825Sdfr
139178825Sdfr    map.start = p;
140178825Sdfr
141178825Sdfr    ret = mprotect ((void *)p, pagesize, 0);
142178825Sdfr    if (ret < 0)
143178825Sdfr	err (1, "mprotect");
144178825Sdfr
145178825Sdfr    ret = mprotect (p + map.size - pagesize, pagesize, 0);
146178825Sdfr    if (ret < 0)
147178825Sdfr	err (1, "mprotect");
148178825Sdfr
149178825Sdfr    switch (type) {
150178825Sdfr    case RK_TM_OVERRUN:
151178825Sdfr	map.data_start = p + map.size - pagesize - size;
152178825Sdfr	break;
153178825Sdfr    case RK_TM_UNDERRUN:
154178825Sdfr	map.data_start = p + pagesize;
155178825Sdfr	break;
156178825Sdfr    default:
157178825Sdfr	abort();
158178825Sdfr    }
159178825Sdfr#endif
160233294Sstas#ifdef HAVE_SIGACTION
161178825Sdfr    sigemptyset (&sa.sa_mask);
162178825Sdfr    sa.sa_flags = 0;
163178825Sdfr#ifdef SA_RESETHAND
164178825Sdfr    sa.sa_flags |= SA_RESETHAND;
165178825Sdfr#endif
166178825Sdfr    sa.sa_handler = segv_handler;
167178825Sdfr    sigaction (SIGSEGV, &sa, &osa);
168233294Sstas#else
169233294Sstas    osigh = signal(SIGSEGV, segv_handler);
170233294Sstas#endif
171178825Sdfr
172178825Sdfr    map.data_size = size;
173178825Sdfr    if (buf)
174178825Sdfr	memcpy(map.data_start, buf, size);
175178825Sdfr    return map.data_start;
176178825Sdfr}
177178825Sdfr
178233294SstasROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
179178825Sdfrrk_test_mem_free(const char *map_name)
180178825Sdfr{
181178825Sdfr#ifndef HAVE_MMAP
182178825Sdfr    unsigned char *p = map.start;
183233294Sstas
184178825Sdfr    if (testname == NULL)
185178825Sdfr	errx(1, "test_mem_free call on no free");
186178825Sdfr
187178825Sdfr    if (p[0] != 0xff)
188178825Sdfr	errx(1, "%s: %s underrun %x\n", testname, map_name, p[0]);
189233294Sstas    if (p[map.size-1] != 0xff)
190178825Sdfr	errx(1, "%s: %s overrun %x\n", testname, map_name, p[map.size - 1]);
191178825Sdfr    free(map.start);
192178825Sdfr#else
193178825Sdfr    int ret;
194233294Sstas
195178825Sdfr    if (testname == NULL)
196178825Sdfr	errx(1, "test_mem_free call on no free");
197178825Sdfr
198178825Sdfr    ret = munmap (map.start, map.size);
199178825Sdfr    if (ret < 0)
200178825Sdfr	err (1, "munmap");
201178825Sdfr    if (map.fd > 0)
202178825Sdfr	close(map.fd);
203178825Sdfr#endif
204178825Sdfr    free(testname);
205178825Sdfr    testname = NULL;
206178825Sdfr
207233294Sstas#ifdef HAVE_SIGACTION
208178825Sdfr    sigaction (SIGSEGV, &osa, NULL);
209233294Sstas#else
210233294Sstas    signal (SIGSEGV, osigh);
211233294Sstas#endif
212178825Sdfr}
213