• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
test_blob_empty(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
free_up(fixture_t * fixture)98 free_up (fixture_t *fixture)
99 {
100   g_assert_cmpint (fixture->freed, ==, 0);
101   fixture->freed++;
102 }
103 
104 static void
free_up_free(fixture_t * fixture)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
get_pagesize(void)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
free_up_munmap(fixture_t * fixture)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
fixture_init(fixture_t * fixture,gconstpointer user_data)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
fixture_finish(fixture_t * fixture,gconstpointer user_data)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
test_blob(fixture_t * fixture,gconstpointer user_data)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
test_blob_subblob(fixture_t * fixture,gconstpointer user_data)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 = 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
main(int argc,char ** argv)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