• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Test program for Linux memory error recovery.
3  * Requires special injection support.
4  *
5  * This is a early primitive version of tinjpage.c,
6  * but simpler to debug in some cases.
7  */
8 #define _GNU_SOURCE 1
9 #include <sys/mman.h>
10 #include <stdio.h>
11 #include <signal.h>
12 #include <unistd.h>
13 #include <sys/fcntl.h>
14 #include <stdlib.h>
15 #include <setjmp.h>
16 #include <errno.h>
17 #include <string.h>
18 
19 #define MADV_POISON 100
20 
21 #define err(x) perror(x),exit(1)
22 
23 int count = 20;
24 int failure = 0;
25 int total_cases = 0;
26 sigjmp_buf recover;
27 int PS;
28 
sighandler(int sig,siginfo_t * si,void * arg)29 void sighandler(int sig, siginfo_t *si, void *arg)
30 {
31 	printf("signal %d code %d addr %p\n", sig, si->si_code, si->si_addr);
32 
33 	if (--count == 0)
34 		exit(1);
35 
36 	siglongjmp(recover, 1);
37 }
38 
testmem(char * msg,char * page,int write)39 void testmem(char *msg, char *page, int write)
40 {
41 	printf("%s page %p\n", msg, page);
42 	total_cases++;
43 	if (sigsetjmp(recover,1) == 0) {
44 		if (madvise(page, PS, MADV_POISON) != 0) {
45 			failure++;
46 			perror("madvise");
47 		}
48 		if (write)
49 			*page = 2;
50 		else
51 			printf("%x\n", *(unsigned char *)page);
52 	}
53 	printf("recovered\n");
54 }
55 
expecterr(char * msg,int res)56 void expecterr(char *msg, int res)
57 {
58 	if (res == 0)
59 		printf("no error on %s\n", msg);
60 	else
61 		perror(msg);
62 }
63 
tempfd(void)64 int tempfd(void)
65 {
66 	static int tmpcount;
67 	int fd;
68 	char buf[30];
69 	snprintf(buf,30,"/tmp/test%d.XXXXXXXX",tmpcount++);
70 	fd = mkstemp(buf);
71 	if (fd >= 0)
72 		unlink(buf);
73 	return fd;
74 }
75 
76 #define RANDOM_FILE "/etc/profile"
77 
main(void)78 int main(void)
79 {
80 	PS = getpagesize();
81 	char *page;
82 
83 	struct sigaction sa = {
84 		.sa_sigaction = sighandler,
85 		.sa_flags = SA_SIGINFO
86 	};
87 	sigaction(SIGBUS, &sa, NULL);
88 //	sigaction(SIGSEGV, &sa, NULL);
89 
90  	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_POPULATE, 0, 0);
91 	testmem("dirty", page, 1);
92 
93 	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, 0, 0);
94 	testmem("mlocked", page, 1);
95 
96 	int fd = open(RANDOM_FILE, O_RDONLY);
97 	if (fd < 0) err("open " RANDOM_FILE);
98 	page = mmap(NULL, PS, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
99 	if (page == (char *)-1) err("mmap");
100 	close(fd);
101 	testmem("clean file", page, 0);
102 
103 	fd = tempfd();
104 	if (fd < 0) err("open testfile");
105 	char *tmp = malloc(PS);
106 	if (!tmp) err("no enough memory");
107 	memset(tmp, 0xff, PS);
108 	write(fd, tmp, PS);
109 	free(tmp);
110 	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
111 	if (page == (char*)-1) err("mmap");
112 	*page = 1;
113 	testmem("file dirty", page, 0);
114 	expecterr("msync expect error", msync(page, PS, MS_SYNC));
115 	expecterr("fsync expect error", fsync(fd));
116 	close(fd);
117 
118 	/* hole case still broken in the kernel -- doesn't report error */
119 	fd = tempfd();
120 	if (fd < 0) err("open testfile");
121 	ftruncate(fd, PS);
122 	page = mmap(NULL, PS, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
123 	if (page == (char*)-1) err("mmap");
124 	*page = 1;
125 	testmem("hole file dirty", page, 0);
126 	expecterr("hole msync expect error", msync(page, PS, MS_SYNC));
127 	expecterr("hole fsync expect error", fsync(fd));
128 	close(fd);
129 
130 #if 0
131 	const int NPAGES = 10;
132 	int i;
133 	fd = tempfd();
134 	if (fd < 0) err("open rfp testfile");
135 	tmp = malloc(PS);
136 	if (!tmp) exit(ENOMEM);
137 	for (i = 0; i < NPAGES; i++)  {
138 		memset(tmp, i, PS);
139 		write(fd, tmp, PS);
140 	}
141 	free(tmp);
142 	page = mmap(NULL, PS*NPAGES, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
143 	if (page == (char*)-1) err("mmap");
144 	int k = NPAGES - 1;
145 	for (i = 0; i < NPAGES; i++, k--) {
146 		if (remap_file_pages(page + i*PS, PS, 0, k, 0))
147 			perror("remap_file_pages");
148 	}
149 	*page = 1;
150 	testmem("rfp file dirty", page, 0);
151 	expecterr("rfp msync expect error", msync(page, PS, MS_SYNC));
152 	expecterr("rfp fsync expect error", fsync(fd));
153 	close(fd);
154 #endif
155 
156 	if (failure > 0) {
157 		printf("FAILURE -- %d of %d cases broken!\n", failure, total_cases);
158 		return 1;
159 	}
160 	printf("SUCCESS\n");
161 
162 	return 0;
163 }
164 
165 
166