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 <pixman-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 43pixman_bool_t verbose; 44 45static void 46segv_handler (int sig, siginfo_t *si, void *unused) 47{ 48 _exit (EXIT_SUCCESS); 49} 50 51static void 52die (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 62static void 63prinfo (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 75static void 76do_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 */ 100static pixman_bool_t 101expect_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 123static void 124read_u8 (void *data) 125{ 126 volatile uint8_t *p = data; 127 128 *p; 129} 130 131static pixman_bool_t 132test_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 148static void 149test_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 159static pixman_bool_t 160test_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 196static pixman_bool_t 197test_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 209int 210main (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 232int 233main (int argc, char **argv) 234{ 235 /* Automake return code for test SKIP. */ 236 return 77; 237} 238 239#endif /* FENCE_MALLOC_ACTIVE */ 240