1/* Test different kinds of addressability and definedness */
2#include "../memcheck.h"
3#include "tests/sys_mman.h"
4#include <stdio.h>
5#include <sys/resource.h>
6#include <unistd.h>
7#include <sys/wait.h>
8#include <assert.h>
9#include <errno.h>
10#include <string.h>
11#include <stdlib.h>
12
13static int pgsz;
14
15static char *mm(char *addr, int size, int prot)
16{
17	int flags = MAP_PRIVATE | MAP_ANONYMOUS;
18	char *ret;
19
20	if (addr)
21		flags |= MAP_FIXED;
22
23	ret = mmap(addr, size, prot, flags, -1, 0);
24	if (ret == (char *)-1) {
25		perror("mmap failed");
26		exit(1);
27	}
28
29	return ret;
30}
31
32/* Case 1 - mmaped memory is defined */
33static void test1()
34{
35	char *m = mm(0, pgsz * 5, PROT_READ);
36
37	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m, pgsz*5); /* all defined */
38}
39
40/* Case 2 - unmapped memory is unaddressable+undefined */
41static void test2()
42{
43	char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
44	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m, pgsz*5); /* all OK */
45
46	munmap(&m[pgsz*2], pgsz);
47
48	(void) VALGRIND_CHECK_MEM_IS_DEFINED(&m[pgsz*2], pgsz); /* undefined */
49
50	/* XXX need a memcheck request to test addressability */
51	m[pgsz*2] = 'x';	/* unmapped fault */
52}
53
54/* Case 3 - memory definedness doesn't survive remapping */
55static void test3()
56{
57	char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
58
59	(void) VALGRIND_MAKE_MEM_UNDEFINED(&m[pgsz], pgsz);
60	mm(&m[pgsz], pgsz, PROT_READ);
61	(void) VALGRIND_CHECK_MEM_IS_DEFINED(&m[pgsz], pgsz); /* OK */
62}
63
64/* Case 4 - mprotect doesn't affect addressability */
65static void test4()
66{
67	char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
68
69	mprotect(m, pgsz, PROT_WRITE);
70	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m, pgsz); /* OK */
71	m[44] = 'y';		/* OK */
72
73	mprotect(m, pgsz*5, PROT_NONE);
74	m[55] = 'x';		/* permission fault, but no tool complaint */
75}
76
77/* Case 5 - mprotect doesn't affect definedness */
78static void test5()
79{
80	char *m = mm(0, pgsz * 5, PROT_READ|PROT_WRITE);
81
82	(void) VALGRIND_MAKE_MEM_UNDEFINED(m, pgsz*5);
83	memset(m, 'x', 10);
84	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m, 10);	/* OK */
85	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m+10, 10); /* BAD */
86
87	mprotect(m, pgsz*5, PROT_NONE);
88	mprotect(m, pgsz*5, PROT_READ);
89
90	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m, 10);	/* still OK */
91	(void) VALGRIND_CHECK_MEM_IS_DEFINED(m+20, 10); /* BAD */
92}
93
94static struct test {
95	void (*test)(void);
96	int faults;
97} tests[] = {
98	{ test1, 0 },
99	{ test2, 1 },
100	{ test3, 0 },
101	{ test4, 1 },
102	{ test5, 0 },
103};
104static const int n_tests = sizeof(tests)/sizeof(*tests);
105
106int main()
107{
108	static const struct rlimit zero = { 0, 0 };
109	int i;
110
111	pgsz = getpagesize();
112	setvbuf(stdout, NULL, _IOLBF, 0);
113
114	setrlimit(RLIMIT_CORE, &zero);
115
116	for(i = 0; i < n_tests; i++) {
117		int pid;
118
119		pid = fork();
120		if (pid == -1) {
121			perror("fork");
122			exit(1);
123		}
124		if (pid == 0) {
125			(*tests[i].test)();
126			exit(0);
127		} else {
128			int status;
129			int ret;
130
131			printf("Test %d: ", i+1);
132			fflush(stdout);
133
134			while((ret = waitpid(pid, &status, 0)) != pid) {
135				if (errno != EINTR) {
136					perror("waitpid");
137					exit(1);
138				}
139			}
140			if (WIFSIGNALED(status)) {
141				assert(WTERMSIG(status) != 0);
142
143				if (1 == tests[i].faults &&
144				    (WTERMSIG(status) == SIGSEGV ||
145				     WTERMSIG(status) == SIGBUS))
146					printf("PASS\n");
147				else
148					printf("died with unexpected signal %d\n",
149					       WTERMSIG(status));
150			} else if (WIFEXITED(status)) {
151				if (WEXITSTATUS(status) == 0) {
152					if (tests[i].faults == 0)
153						printf("PASS\n");
154					else
155						printf("exited without expected SIGSEGV or SIGBUS signal\n");
156				} else
157					printf("exited with unexpected status %d\n",
158					       WEXITSTATUS(status));
159			} else {
160				printf("strange status %x?\n", status);
161			}
162		}
163	}
164	exit(0);
165}
166