1 /* 2 * Copyright 2009 Red Hat, 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 * Red Hat Author(s): Behdad Esfahbod 25 */ 26 27 /* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */ 28 #ifndef _POSIX_C_SOURCE 29 #define _POSIX_C_SOURCE 199309L 30 #endif 31 32 #include "hb-private.hh" 33 34 #include "hb-object-private.hh" 35 36 #ifdef HAVE_SYS_MMAN_H 37 #ifdef HAVE_UNISTD_H 38 #include <unistd.h> 39 #endif /* HAVE_UNISTD_H */ 40 #include <sys/mman.h> 41 #endif /* HAVE_SYS_MMAN_H */ 42 43 #include <stdio.h> 44 #include <errno.h> 45 46 47 48 #ifndef HB_DEBUG_BLOB 49 #define HB_DEBUG_BLOB (HB_DEBUG+0) 50 #endif 51 52 53 struct hb_blob_t { 54 hb_object_header_t header; 55 ASSERT_POD (); 56 57 bool immutable; 58 59 const char *data; 60 unsigned int length; 61 hb_memory_mode_t mode; 62 63 void *user_data; 64 hb_destroy_func_t destroy; 65 }; 66 67 68 static bool _try_writable (hb_blob_t *blob); 69 70 static void 71 _hb_blob_destroy_user_data (hb_blob_t *blob) 72 { 73 if (blob->destroy) { 74 blob->destroy (blob->user_data); 75 blob->user_data = NULL; 76 blob->destroy = NULL; 77 } 78 } 79 80 /** 81 * hb_blob_create: (Xconstructor) 82 * @data: (array length=length) (closure user_data) (destroy destroy) (scope notified) (transfer none): Pointer to blob data. 83 * @length: Length of @data in bytes. 84 * @mode: Memory mode for @data. 85 * @user_data: Data parameter to pass to @destroy. 86 * @destroy: Callback to call when @data is not needed anymore. 87 * 88 * Creates a new "blob" object wrapping @data. The @mode parameter is used 89 * to negotiate ownership and lifecycle of @data. 90 * 91 * Return value: New blob, or the empty blob if something failed or if @length is 92 * zero. Destroy with hb_blob_destroy(). 93 * 94 * Since: 1.0 95 **/ 96 hb_blob_t * 97 hb_blob_create (const char *data, 98 unsigned int length, 99 hb_memory_mode_t mode, 100 void *user_data, 101 hb_destroy_func_t destroy) 102 { 103 hb_blob_t *blob; 104 105 if (!length || !(blob = hb_object_create<hb_blob_t> ())) { 106 if (destroy) 107 destroy (user_data); 108 return hb_blob_get_empty (); 109 } 110 111 blob->data = data; 112 blob->length = length; 113 blob->mode = mode; 114 115 blob->user_data = user_data; 116 blob->destroy = destroy; 117 118 if (blob->mode == HB_MEMORY_MODE_DUPLICATE) { 119 blob->mode = HB_MEMORY_MODE_READONLY; 120 if (!_try_writable (blob)) { 121 hb_blob_destroy (blob); 122 return hb_blob_get_empty (); 123 } 124 } 125 126 return blob; 127 } 128 129 /** 130 * hb_blob_create_sub_blob: 131 * @parent: Parent blob. 132 * @offset: Start offset of sub-blob within @parent, in bytes. 133 * @length: Length of sub-blob. 134 * 135 * Returns a blob that represents a range of bytes in @parent. The new 136 * blob is always created with %HB_MEMORY_MODE_READONLY, meaning that it 137 * will never modify data in the parent blob. The parent data is not 138 * expected to be modified, and will result in undefined behavior if it 139 * is. 140 * 141 * Makes @parent immutable. 142 * 143 * Return value: New blob, or the empty blob if something failed or if 144 * @length is zero or @offset is beyond the end of @parent's data. Destroy 145 * with hb_blob_destroy(). 146 * 147 * Since: 1.0 148 **/ 149 hb_blob_t * 150 hb_blob_create_sub_blob (hb_blob_t *parent, 151 unsigned int offset, 152 unsigned int length) 153 { 154 hb_blob_t *blob; 155 156 if (!length || offset >= parent->length) 157 return hb_blob_get_empty (); 158 159 hb_blob_make_immutable (parent); 160 161 blob = hb_blob_create (parent->data + offset, 162 MIN (length, parent->length - offset), 163 HB_MEMORY_MODE_READONLY, 164 hb_blob_reference (parent), 165 (hb_destroy_func_t) hb_blob_destroy); 166 167 return blob; 168 } 169 170 /** 171 * hb_blob_get_empty: 172 * 173 * Returns the singleton empty blob. 174 * 175 * See TODO:link object types for more information. 176 * 177 * Return value: (transfer full): the empty blob. 178 * 179 * Since: 1.0 180 **/ 181 hb_blob_t * 182 hb_blob_get_empty (void) 183 { 184 static const hb_blob_t _hb_blob_nil = { 185 HB_OBJECT_HEADER_STATIC, 186 187 true, /* immutable */ 188 189 NULL, /* data */ 190 0, /* length */ 191 HB_MEMORY_MODE_READONLY, /* mode */ 192 193 NULL, /* user_data */ 194 NULL /* destroy */ 195 }; 196 197 return const_cast<hb_blob_t *> (&_hb_blob_nil); 198 } 199 200 /** 201 * hb_blob_reference: (skip) 202 * @blob: a blob. 203 * 204 * Increases the reference count on @blob. 205 * 206 * See TODO:link object types for more information. 207 * 208 * Return value: @blob. 209 * 210 * Since: 1.0 211 **/ 212 hb_blob_t * 213 hb_blob_reference (hb_blob_t *blob) 214 { 215 return hb_object_reference (blob); 216 } 217 218 /** 219 * hb_blob_destroy: (skip) 220 * @blob: a blob. 221 * 222 * Descreases the reference count on @blob, and if it reaches zero, destroys 223 * @blob, freeing all memory, possibly calling the destroy-callback the blob 224 * was created for if it has not been called already. 225 * 226 * See TODO:link object types for more information. 227 * 228 * Since: 1.0 229 **/ 230 void 231 hb_blob_destroy (hb_blob_t *blob) 232 { 233 if (!hb_object_destroy (blob)) return; 234 235 _hb_blob_destroy_user_data (blob); 236 237 free (blob); 238 } 239 240 /** 241 * hb_blob_set_user_data: (skip) 242 * @blob: a blob. 243 * @key: key for data to set. 244 * @data: data to set. 245 * @destroy: callback to call when @data is not needed anymore. 246 * @replace: whether to replace an existing data with the same key. 247 * 248 * Return value: 249 * 250 * Since: 1.0 251 **/ 252 hb_bool_t 253 hb_blob_set_user_data (hb_blob_t *blob, 254 hb_user_data_key_t *key, 255 void * data, 256 hb_destroy_func_t destroy, 257 hb_bool_t replace) 258 { 259 return hb_object_set_user_data (blob, key, data, destroy, replace); 260 } 261 262 /** 263 * hb_blob_get_user_data: (skip) 264 * @blob: a blob. 265 * @key: key for data to get. 266 * 267 * 268 * 269 * Return value: (transfer none): 270 * 271 * Since: 1.0 272 **/ 273 void * 274 hb_blob_get_user_data (hb_blob_t *blob, 275 hb_user_data_key_t *key) 276 { 277 return hb_object_get_user_data (blob, key); 278 } 279 280 281 /** 282 * hb_blob_make_immutable: 283 * @blob: a blob. 284 * 285 * 286 * 287 * Since: 1.0 288 **/ 289 void 290 hb_blob_make_immutable (hb_blob_t *blob) 291 { 292 if (hb_object_is_inert (blob)) 293 return; 294 295 blob->immutable = true; 296 } 297 298 /** 299 * hb_blob_is_immutable: 300 * @blob: a blob. 301 * 302 * 303 * 304 * Return value: TODO 305 * 306 * Since: 1.0 307 **/ 308 hb_bool_t 309 hb_blob_is_immutable (hb_blob_t *blob) 310 { 311 return blob->immutable; 312 } 313 314 315 /** 316 * hb_blob_get_length: 317 * @blob: a blob. 318 * 319 * 320 * 321 * Return value: the length of blob data in bytes. 322 * 323 * Since: 1.0 324 **/ 325 unsigned int 326 hb_blob_get_length (hb_blob_t *blob) 327 { 328 return blob->length; 329 } 330 331 /** 332 * hb_blob_get_data: 333 * @blob: a blob. 334 * @length: (out): 335 * 336 * 337 * 338 * Returns: (transfer none) (array length=length): 339 * 340 * Since: 1.0 341 **/ 342 const char * 343 hb_blob_get_data (hb_blob_t *blob, unsigned int *length) 344 { 345 if (length) 346 *length = blob->length; 347 348 return blob->data; 349 } 350 351 /** 352 * hb_blob_get_data_writable: 353 * @blob: a blob. 354 * @length: (out): output length of the writable data. 355 * 356 * Tries to make blob data writable (possibly copying it) and 357 * return pointer to data. 358 * 359 * Fails if blob has been made immutable, or if memory allocation 360 * fails. 361 * 362 * Returns: (transfer none) (array length=length): Writable blob data, 363 * or %NULL if failed. 364 * 365 * Since: 1.0 366 **/ 367 char * 368 hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length) 369 { 370 if (!_try_writable (blob)) { 371 if (length) 372 *length = 0; 373 374 return NULL; 375 } 376 377 if (length) 378 *length = blob->length; 379 380 return const_cast<char *> (blob->data); 381 } 382 383 384 static hb_bool_t 385 _try_make_writable_inplace_unix (hb_blob_t *blob) 386 { 387 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT) 388 uintptr_t pagesize = -1, mask, length; 389 const char *addr; 390 391 #if defined(HAVE_SYSCONF) && defined(_SC_PAGE_SIZE) 392 pagesize = (uintptr_t) sysconf (_SC_PAGE_SIZE); 393 #elif defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) 394 pagesize = (uintptr_t) sysconf (_SC_PAGESIZE); 395 #elif defined(HAVE_GETPAGESIZE) 396 pagesize = (uintptr_t) getpagesize (); 397 #endif 398 399 if ((uintptr_t) -1L == pagesize) { 400 DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno)); 401 return false; 402 } 403 DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize); 404 405 mask = ~(pagesize-1); 406 addr = (const char *) (((uintptr_t) blob->data) & mask); 407 length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr; 408 DEBUG_MSG_FUNC (BLOB, blob, 409 "calling mprotect on [%p..%p] (%lu bytes)", 410 addr, addr+length, (unsigned long) length); 411 if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) { 412 DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno)); 413 return false; 414 } 415 416 blob->mode = HB_MEMORY_MODE_WRITABLE; 417 418 DEBUG_MSG_FUNC (BLOB, blob, 419 "successfully made [%p..%p] (%lu bytes) writable\n", 420 addr, addr+length, (unsigned long) length); 421 return true; 422 #else 423 return false; 424 #endif 425 } 426 427 static bool 428 _try_writable_inplace (hb_blob_t *blob) 429 { 430 DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n"); 431 432 if (_try_make_writable_inplace_unix (blob)) 433 return true; 434 435 DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n"); 436 437 /* Failed to make writable inplace, mark that */ 438 blob->mode = HB_MEMORY_MODE_READONLY; 439 return false; 440 } 441 442 static bool 443 _try_writable (hb_blob_t *blob) 444 { 445 if (blob->immutable) 446 return false; 447 448 if (blob->mode == HB_MEMORY_MODE_WRITABLE) 449 return true; 450 451 if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob)) 452 return true; 453 454 if (blob->mode == HB_MEMORY_MODE_WRITABLE) 455 return true; 456 457 458 DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data); 459 460 char *new_data; 461 462 new_data = (char *) malloc (blob->length); 463 if (unlikely (!new_data)) 464 return false; 465 466 DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data); 467 468 memcpy (new_data, blob->data, blob->length); 469 _hb_blob_destroy_user_data (blob); 470 blob->mode = HB_MEMORY_MODE_WRITABLE; 471 blob->data = new_data; 472 blob->user_data = new_data; 473 blob->destroy = free; 474 475 return true; 476 } 477