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