• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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