1 /* 2 * Copyright 2011 Google, Inc. 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 * 24 * Google Author(s): Behdad Esfahbod 25 */ 26 27 #include "hb-test.h" 28 29 /* Unit tests for hb-blob.h */ 30 31 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) && defined(HAVE_MMAP) 32 33 # define TEST_MMAP 1 34 35 #ifdef HAVE_SYS_MMAN_H 36 #ifdef HAVE_UNISTD_H 37 #include <unistd.h> 38 #endif /* HAVE_UNISTD_H */ 39 #include <sys/mman.h> 40 #endif /* HAVE_SYS_MMAN_H */ 41 42 #endif 43 44 45 static void 46 test_blob_empty (void) 47 { 48 hb_blob_t *blob; 49 unsigned int len; 50 const char *data; 51 char *data_writable; 52 53 g_assert (hb_blob_is_immutable (hb_blob_get_empty ())); 54 g_assert (hb_blob_get_empty () != NULL); 55 g_assert (hb_blob_get_empty () == hb_blob_create (NULL, 0, HB_MEMORY_MODE_READONLY, NULL, NULL)); 56 57 blob = hb_blob_get_empty (); 58 g_assert (blob == hb_blob_get_empty ()); 59 60 len = hb_blob_get_length (blob); 61 g_assert_cmpint (len, ==, 0); 62 63 data = hb_blob_get_data (blob, NULL); 64 g_assert (data == NULL); 65 66 data = hb_blob_get_data (blob, &len); 67 g_assert (data == NULL); 68 g_assert_cmpint (len, ==, 0); 69 70 data_writable = hb_blob_get_data_writable (blob, NULL); 71 g_assert (data_writable == NULL); 72 73 data_writable = hb_blob_get_data_writable (blob, &len); 74 g_assert (data_writable == NULL); 75 g_assert_cmpint (len, ==, 0); 76 } 77 78 static const char test_data[] = "test\0data"; 79 80 static const char *blob_names[] = { 81 "duplicate", 82 "readonly", 83 "writable" 84 #ifdef TEST_MMAP 85 , "readonly-may-make-writable" 86 #endif 87 }; 88 89 typedef struct 90 { 91 hb_blob_t *blob; 92 int freed; 93 char *data; 94 unsigned int len; 95 } fixture_t; 96 97 static void 98 free_up (fixture_t *fixture) 99 { 100 g_assert_cmpint (fixture->freed, ==, 0); 101 fixture->freed++; 102 } 103 104 static void 105 free_up_free (fixture_t *fixture) 106 { 107 free_up (fixture); 108 free (fixture->data); 109 } 110 111 112 #ifdef TEST_MMAP 113 static uintptr_t 114 get_pagesize (void) 115 { 116 uintptr_t pagesize = -1; 117 118 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) 119 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); 120 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) 121 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); 122 #elif defined(HAVE_GETPAGESIZE) 123 pagesize = (uintptr_t) getpagesize (); 124 #endif 125 126 g_assert (pagesize != (uintptr_t) -1); 127 128 return pagesize; 129 } 130 131 static void 132 free_up_munmap (fixture_t *fixture) 133 { 134 free_up (fixture); 135 munmap (fixture->data, get_pagesize ()); 136 } 137 #endif 138 139 #include <errno.h> 140 static void 141 fixture_init (fixture_t *fixture, gconstpointer user_data) 142 { 143 hb_memory_mode_t mm = (hb_memory_mode_t) GPOINTER_TO_INT (user_data); 144 unsigned int len; 145 const char *data; 146 hb_destroy_func_t free_func; 147 148 switch (GPOINTER_TO_INT (user_data)) 149 { 150 case HB_MEMORY_MODE_DUPLICATE: 151 data = test_data; 152 len = sizeof (test_data); 153 free_func = (hb_destroy_func_t) free_up; 154 break; 155 156 case HB_MEMORY_MODE_READONLY: 157 data = test_data; 158 len = sizeof (test_data); 159 free_func = (hb_destroy_func_t) free_up; 160 break; 161 162 case HB_MEMORY_MODE_WRITABLE: 163 data = malloc (sizeof (test_data)); 164 memcpy ((char *) data, test_data, sizeof (test_data)); 165 len = sizeof (test_data); 166 free_func = (hb_destroy_func_t) free_up_free; 167 break; 168 169 #ifdef TEST_MMAP 170 case HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE: 171 { 172 uintptr_t pagesize = get_pagesize (); 173 174 data = mmap (NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 175 g_assert (data != (char *) -1); 176 memcpy ((char *) data, test_data, sizeof (test_data)); 177 mprotect ((char *) data, pagesize, PROT_READ); 178 len = sizeof (test_data); 179 free_func = (hb_destroy_func_t) free_up_munmap; 180 break; 181 } 182 #endif 183 184 default: 185 g_assert_not_reached (); 186 } 187 188 fixture->freed = 0; 189 fixture->data = (char *) data; 190 fixture->len = len; 191 fixture->blob = hb_blob_create (data, len, mm, fixture, free_func); 192 } 193 194 static void 195 fixture_finish (fixture_t *fixture, gconstpointer user_data) 196 { 197 hb_blob_destroy (fixture->blob); 198 g_assert_cmpint (fixture->freed, ==, 1); 199 } 200 201 202 static void 203 test_blob (fixture_t *fixture, gconstpointer user_data) 204 { 205 hb_blob_t *b = fixture->blob; 206 hb_memory_mode_t mm = GPOINTER_TO_INT (user_data); 207 unsigned int len; 208 const char *data; 209 char *data_writable; 210 unsigned int i; 211 212 g_assert (b); 213 214 len = hb_blob_get_length (b); 215 g_assert_cmpint (len, ==, fixture->len); 216 217 data = hb_blob_get_data (b, &len); 218 g_assert_cmpint (len, ==, fixture->len); 219 if (mm == HB_MEMORY_MODE_DUPLICATE) { 220 g_assert (data != fixture->data); 221 g_assert_cmpint (fixture->freed, ==, 1); 222 mm = HB_MEMORY_MODE_WRITABLE; 223 } else { 224 g_assert (data == fixture->data); 225 g_assert_cmpint (fixture->freed, ==, 0); 226 } 227 228 data_writable = hb_blob_get_data_writable (b, &len); 229 g_assert_cmpint (len, ==, fixture->len); 230 g_assert (data_writable); 231 g_assert (0 == memcmp (data_writable, fixture->data, fixture->len)); 232 if (mm == HB_MEMORY_MODE_READONLY) { 233 g_assert (data_writable != data); 234 g_assert_cmpint (fixture->freed, ==, 1); 235 } else { 236 g_assert (data_writable == data); 237 } 238 239 data = hb_blob_get_data (b, &len); 240 g_assert_cmpint (len, ==, fixture->len); 241 g_assert (data == data_writable); 242 243 memset (data_writable, 0, fixture->len); 244 245 /* Now, make it immutable and watch get_data_writable() fail */ 246 247 g_assert (!hb_blob_is_immutable (b)); 248 hb_blob_make_immutable (b); 249 g_assert (hb_blob_is_immutable (b)); 250 251 data_writable = hb_blob_get_data_writable (b, &len); 252 g_assert (!data_writable); 253 g_assert_cmpint (len, ==, 0); 254 255 data = hb_blob_get_data (b, &len); 256 g_assert_cmpint (len, ==, fixture->len); 257 for (i = 0; i < len; i++) 258 g_assert ('\0' == data[i]); 259 } 260 261 static void 262 test_blob_subblob (fixture_t *fixture, gconstpointer user_data) 263 { 264 hb_blob_t *b = fixture->blob; 265 hb_memory_mode_t mm = GPOINTER_TO_INT (user_data); 266 unsigned int len; 267 const char *data; 268 char *data_writable; 269 unsigned int i; 270 271 if (mm == HB_MEMORY_MODE_DUPLICATE) { 272 g_assert_cmpint (fixture->freed, ==, 1); 273 fixture->data = (char *) hb_blob_get_data (b, NULL); 274 } else { 275 g_assert_cmpint (fixture->freed, ==, 0); 276 } 277 fixture->blob = hb_blob_create_sub_blob (b, 1, fixture->len - 2); 278 hb_blob_destroy (b); 279 b = fixture->blob; 280 281 /* A sub-blob is always created READONLY. */ 282 283 g_assert (b); 284 285 len = hb_blob_get_length (b); 286 g_assert_cmpint (len, ==, fixture->len - 2); 287 288 data = hb_blob_get_data (b, &len); 289 g_assert_cmpint (len, ==, fixture->len - 2); 290 g_assert (data == fixture->data + 1); 291 292 data_writable = hb_blob_get_data_writable (b, &len); 293 g_assert_cmpint (len, ==, fixture->len - 2); 294 g_assert (data_writable); 295 if (mm == HB_MEMORY_MODE_READONLY) 296 g_assert (0 == memcmp (data_writable, fixture->data + 1, fixture->len - 2)); 297 g_assert (data_writable != data); 298 g_assert_cmpint (fixture->freed, ==, 1); 299 300 data = hb_blob_get_data (b, &len); 301 g_assert_cmpint (len, ==, fixture->len - 2); 302 g_assert (data == data_writable); 303 304 memset (data_writable, 0, fixture->len - 2); 305 306 /* Now, make it immutable and watch get_data_writable() fail */ 307 308 g_assert (!hb_blob_is_immutable (b)); 309 hb_blob_make_immutable (b); 310 g_assert (hb_blob_is_immutable (b)); 311 312 data_writable = hb_blob_get_data_writable (b, &len); 313 g_assert (!data_writable); 314 g_assert_cmpint (len, ==, 0); 315 316 data = hb_blob_get_data (b, &len); 317 g_assert_cmpint (len, ==, fixture->len - 2); 318 for (i = 0; i < len; i++) 319 g_assert ('\0' == data[i]); 320 } 321 322 323 int 324 main (int argc, char **argv) 325 { 326 unsigned int i; 327 328 hb_test_init (&argc, &argv); 329 330 hb_test_add (test_blob_empty); 331 332 for (i = 0; i < G_N_ELEMENTS (blob_names); i++) 333 { 334 const void *blob_type = GINT_TO_POINTER (i); 335 const char *blob_name = blob_names[i]; 336 337 hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob); 338 hb_test_add_fixture_flavor (fixture, blob_type, blob_name, test_blob_subblob); 339 } 340 341 /* 342 * create_sub_blob 343 */ 344 345 return hb_test_run (); 346 } 347