LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-blob.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 34 94 36.2 %
Date: 2017-07-14 16:53:18 Functions: 8 16 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           9 : _hb_blob_destroy_user_data (hb_blob_t *blob)
      72             : {
      73           9 :   if (blob->destroy) {
      74           9 :     blob->destroy (blob->user_data);
      75           9 :     blob->user_data = NULL;
      76           9 :     blob->destroy = NULL;
      77             :   }
      78           9 : }
      79             : 
      80             : /**
      81             :  * hb_blob_create: (skip)
      82             :  * @data: 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: 0.9.2
      95             :  **/
      96             : hb_blob_t *
      97          14 : 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          28 :   if (!length ||
     106          28 :       length >= 1u << 31 ||
     107             :       !(blob = hb_object_create<hb_blob_t> ())) {
     108           0 :     if (destroy)
     109           0 :       destroy (user_data);
     110           0 :     return hb_blob_get_empty ();
     111             :   }
     112             : 
     113          14 :   blob->data = data;
     114          14 :   blob->length = length;
     115          14 :   blob->mode = mode;
     116             : 
     117          14 :   blob->user_data = user_data;
     118          14 :   blob->destroy = destroy;
     119             : 
     120          14 :   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
     121           0 :     blob->mode = HB_MEMORY_MODE_READONLY;
     122           0 :     if (!_try_writable (blob)) {
     123           0 :       hb_blob_destroy (blob);
     124           0 :       return hb_blob_get_empty ();
     125             :     }
     126             :   }
     127             : 
     128          14 :   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: 0.9.2
     150             :  **/
     151             : hb_blob_t *
     152           0 : 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           0 :   if (!length || offset >= parent->length)
     159           0 :     return hb_blob_get_empty ();
     160             : 
     161           0 :   hb_blob_make_immutable (parent);
     162             : 
     163           0 :   blob = hb_blob_create (parent->data + offset,
     164           0 :                          MIN (length, parent->length - offset),
     165             :                          HB_MEMORY_MODE_READONLY,
     166           0 :                          hb_blob_reference (parent),
     167           0 :                          (hb_destroy_func_t) hb_blob_destroy);
     168             : 
     169           0 :   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: 0.9.2
     182             :  **/
     183             : hb_blob_t *
     184          16 : 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          16 :   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: 0.9.2
     213             :  **/
     214             : hb_blob_t *
     215          15 : hb_blob_reference (hb_blob_t *blob)
     216             : {
     217          15 :   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: 0.9.2
     231             :  **/
     232             : void
     233          30 : hb_blob_destroy (hb_blob_t *blob)
     234             : {
     235          30 :   if (!hb_object_destroy (blob)) return;
     236             : 
     237           9 :   _hb_blob_destroy_user_data (blob);
     238             : 
     239           9 :   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: 0.9.2
     253             :  **/
     254             : hb_bool_t
     255           0 : 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           0 :   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: 0.9.2
     274             :  **/
     275             : void *
     276           0 : hb_blob_get_user_data (hb_blob_t          *blob,
     277             :                        hb_user_data_key_t *key)
     278             : {
     279           0 :   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: 0.9.2
     290             :  **/
     291             : void
     292          14 : hb_blob_make_immutable (hb_blob_t *blob)
     293             : {
     294          14 :   if (hb_object_is_inert (blob))
     295           2 :     return;
     296             : 
     297          12 :   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: 0.9.2
     309             :  **/
     310             : hb_bool_t
     311           0 : hb_blob_is_immutable (hb_blob_t *blob)
     312             : {
     313           0 :   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: 0.9.2
     326             :  **/
     327             : unsigned int
     328          26 : hb_blob_get_length (hb_blob_t *blob)
     329             : {
     330          26 :   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: 0.9.2
     343             :  **/
     344             : const char *
     345          30 : hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
     346             : {
     347          30 :   if (length)
     348           2 :     *length = blob->length;
     349             : 
     350          30 :   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: 0.9.2
     368             :  **/
     369             : char *
     370           0 : hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
     371             : {
     372           0 :   if (!_try_writable (blob)) {
     373           0 :     if (length)
     374           0 :       *length = 0;
     375             : 
     376           0 :     return NULL;
     377             :   }
     378             : 
     379           0 :   if (length)
     380           0 :     *length = blob->length;
     381             : 
     382           0 :   return const_cast<char *> (blob->data);
     383             : }
     384             : 
     385             : 
     386             : static hb_bool_t
     387           0 : _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           0 :   return false;
     426             : #endif
     427             : }
     428             : 
     429             : static bool
     430           0 : _try_writable_inplace (hb_blob_t *blob)
     431             : {
     432           0 :   DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
     433             : 
     434           0 :   if (_try_make_writable_inplace_unix (blob))
     435           0 :     return true;
     436             : 
     437           0 :   DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
     438             : 
     439             :   /* Failed to make writable inplace, mark that */
     440           0 :   blob->mode = HB_MEMORY_MODE_READONLY;
     441           0 :   return false;
     442             : }
     443             : 
     444             : static bool
     445           0 : _try_writable (hb_blob_t *blob)
     446             : {
     447           0 :   if (blob->immutable)
     448           0 :     return false;
     449             : 
     450           0 :   if (blob->mode == HB_MEMORY_MODE_WRITABLE)
     451           0 :     return true;
     452             : 
     453           0 :   if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
     454           0 :     return true;
     455             : 
     456           0 :   if (blob->mode == HB_MEMORY_MODE_WRITABLE)
     457           0 :     return true;
     458             : 
     459             : 
     460           0 :   DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
     461             : 
     462             :   char *new_data;
     463             : 
     464           0 :   new_data = (char *) malloc (blob->length);
     465           0 :   if (unlikely (!new_data))
     466           0 :     return false;
     467             : 
     468           0 :   DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
     469             : 
     470           0 :   memcpy (new_data, blob->data, blob->length);
     471           0 :   _hb_blob_destroy_user_data (blob);
     472           0 :   blob->mode = HB_MEMORY_MODE_WRITABLE;
     473           0 :   blob->data = new_data;
     474           0 :   blob->user_data = new_data;
     475           0 :   blob->destroy = free;
     476             : 
     477           0 :   return true;
     478             : }

Generated by: LCOV version 1.13