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