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 
13 static int pgsz;
14 
mm(char * addr,int size,int prot)15 static 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 */
test1()33 static 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 */
test2()41 static 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 */
test3()55 static 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 */
test4()65 static 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 */
test5()78 static 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 
94 static 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 };
104 static const int n_tests = sizeof(tests)/sizeof(*tests);
105 
main()106 int 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