1 /*
2 * Copyright © 2015 Raspberry Pi Foundation
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. The copyright holders make no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
19 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
20 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21 * SOFTWARE.
22 *
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include "utils.h"
30
31
32 #if FENCE_MALLOC_ACTIVE && defined (HAVE_SIGACTION)
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <errno.h>
38 #include <signal.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42
43 pixman_bool_t verbose;
44
45 static void
segv_handler(int sig,siginfo_t * si,void * unused)46 segv_handler (int sig, siginfo_t *si, void *unused)
47 {
48 _exit (EXIT_SUCCESS);
49 }
50
51 static void
die(const char * msg,int err)52 die (const char *msg, int err)
53 {
54 if (err)
55 perror (msg);
56 else
57 fprintf (stderr, "%s\n", msg);
58
59 abort ();
60 }
61
62 static void
prinfo(const char * fmt,...)63 prinfo (const char *fmt, ...)
64 {
65 va_list ap;
66
67 if (!verbose)
68 return;
69
70 va_start (ap, fmt);
71 vfprintf (stderr, fmt, ap);
72 va_end (ap);
73 }
74
75 static void
do_expect_signal(void (* fn)(void *),void * data)76 do_expect_signal (void (*fn)(void *), void *data)
77 {
78 struct sigaction sa;
79
80 sa.sa_flags = SA_SIGINFO;
81 sigemptyset (&sa.sa_mask);
82 sa.sa_sigaction = segv_handler;
83 if (sigaction (SIGSEGV, &sa, NULL) == -1)
84 die ("sigaction failed", errno);
85 if (sigaction (SIGBUS, &sa, NULL) == -1)
86 die ("sigaction failed", errno);
87
88 (*fn)(data);
89
90 _exit (EXIT_FAILURE);
91 }
92
93 /* Check that calling fn(data) causes a segmentation fault.
94 *
95 * You cannot portably return from a SIGSEGV handler in any way,
96 * so we fork, and do the test in the child process. Child's
97 * exit status will reflect the result. Its SEGV handler causes it
98 * to exit with success, and return failure otherwise.
99 */
100 static pixman_bool_t
expect_signal(void (* fn)(void *),void * data)101 expect_signal (void (*fn)(void *), void *data)
102 {
103 pid_t pid, wp;
104 int status;
105
106 pid = fork ();
107 if (pid == -1)
108 die ("fork failed", errno);
109
110 if (pid == 0)
111 do_expect_signal (fn, data); /* never returns */
112
113 wp = waitpid (pid, &status, 0);
114 if (wp != pid)
115 die ("waitpid did not work", wp == -1 ? errno : 0);
116
117 if (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_SUCCESS)
118 return TRUE;
119
120 return FALSE;
121 }
122
123 static void
read_u8(void * data)124 read_u8 (void *data)
125 {
126 volatile uint8_t *p = data;
127
128 *p;
129 }
130
131 static pixman_bool_t
test_read_fault(uint8_t * p,int offset)132 test_read_fault (uint8_t *p, int offset)
133 {
134 prinfo ("*(uint8_t *)(%p + %d)", p, offset);
135
136 if (expect_signal (read_u8, p + offset))
137 {
138 prinfo ("\tsignal OK\n");
139
140 return TRUE;
141 }
142
143 prinfo ("\tFAILED\n");
144
145 return FALSE;
146 }
147
148 static void
test_read_ok(uint8_t * p,int offset)149 test_read_ok (uint8_t *p, int offset)
150 {
151 prinfo ("*(uint8_t *)(%p + %d)", p, offset);
152
153 /* If fails, SEGV. */
154 read_u8 (p + offset);
155
156 prinfo ("\tOK\n");
157 }
158
159 static pixman_bool_t
test_read_faults(pixman_image_t * image)160 test_read_faults (pixman_image_t *image)
161 {
162 pixman_bool_t ok = TRUE;
163 pixman_format_code_t format = pixman_image_get_format (image);
164 int width = pixman_image_get_width (image);
165 int height = pixman_image_get_height (image);
166 int stride = pixman_image_get_stride (image);
167 uint8_t *p = (void *)pixman_image_get_data (image);
168 int row_bytes = width * PIXMAN_FORMAT_BPP (format) / 8;
169
170 prinfo ("%s %dx%d, row %d B, stride %d B:\n",
171 format_name (format), width, height, row_bytes, stride);
172
173 assert (height > 3);
174
175 test_read_ok (p, 0);
176 test_read_ok (p, row_bytes - 1);
177 test_read_ok (p, stride);
178 test_read_ok (p, stride + row_bytes - 1);
179 test_read_ok (p, 2 * stride);
180 test_read_ok (p, 2 * stride + row_bytes - 1);
181 test_read_ok (p, 3 * stride);
182 test_read_ok (p, (height - 1) * stride + row_bytes - 1);
183
184 ok &= test_read_fault (p, -1);
185 ok &= test_read_fault (p, row_bytes);
186 ok &= test_read_fault (p, stride - 1);
187 ok &= test_read_fault (p, stride + row_bytes);
188 ok &= test_read_fault (p, 2 * stride - 1);
189 ok &= test_read_fault (p, 2 * stride + row_bytes);
190 ok &= test_read_fault (p, 3 * stride - 1);
191 ok &= test_read_fault (p, height * stride);
192
193 return ok;
194 }
195
196 static pixman_bool_t
test_image_faults(pixman_format_code_t format,int min_width,int height)197 test_image_faults (pixman_format_code_t format, int min_width, int height)
198 {
199 pixman_bool_t ok;
200 pixman_image_t *image;
201
202 image = fence_image_create_bits (format, min_width, height, TRUE);
203 ok = test_read_faults (image);
204 pixman_image_unref (image);
205
206 return ok;
207 }
208
209 int
main(int argc,char ** argv)210 main (int argc, char **argv)
211 {
212 pixman_bool_t ok = TRUE;
213
214 if (getenv ("VERBOSE") != NULL)
215 verbose = TRUE;
216
217 ok &= test_image_faults (PIXMAN_a8r8g8b8, 7, 5);
218 ok &= test_image_faults (PIXMAN_r8g8b8, 7, 5);
219 ok &= test_image_faults (PIXMAN_r5g6b5, 7, 5);
220 ok &= test_image_faults (PIXMAN_a8, 7, 5);
221 ok &= test_image_faults (PIXMAN_a4, 7, 5);
222 ok &= test_image_faults (PIXMAN_a1, 7, 5);
223
224 if (ok)
225 return EXIT_SUCCESS;
226
227 return EXIT_FAILURE;
228 }
229
230 #else /* FENCE_MALLOC_ACTIVE */
231
232 int
main(int argc,char ** argv)233 main (int argc, char **argv)
234 {
235 /* Automake return code for test SKIP. */
236 return 77;
237 }
238
239 #endif /* FENCE_MALLOC_ACTIVE */
240