1 /* Copyright (C) 2001-2012 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied,
8    modified or distributed except as expressly authorized under the terms
9    of the license contained in the file LICENSE in this distribution.
10 
11    Refer to licensing information at http://www.artifex.com or contact
12    Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134, San Rafael,
13    CA  94903, U.S.A., +1(415)492-9861, for further information.
14 */
15 
16 
17 /* Generic allocator support */
18 #include "memory_.h"
19 #include "gdebug.h"
20 #include "gstypes.h"
21 #include "gsmemory.h"
22 #include "gsmdebug.h"
23 #include "gsrefct.h"		/* to check prototype */
24 #include "gsstruct.h"		/* ditto */
25 
26 /* Define the fill patterns for unallocated memory. */
27 const byte gs_alloc_fill_alloc = 0xa1;
28 const byte gs_alloc_fill_block = 0xb1;
29 const byte gs_alloc_fill_collected = 0xc1;
30 const byte gs_alloc_fill_deleted = 0xd1;
31 const byte gs_alloc_fill_free = 0xf1;
32 
33 /* A 'structure' type descriptor for free blocks. */
34 gs_public_st_simple(st_free, byte, "(free)");
35 
36 /* The 'structure' type descriptor for bytes. */
37 gs_public_st_simple(st_bytes, byte, "bytes");
38 
39 /* The structure type descriptor for GC roots. */
40 public_st_gc_root_t();
41 
42 /* The descriptors for elements and arrays of const strings. */
43 private_st_const_string();
44 public_st_const_string_element();
45 
46 /* GC procedures for bytestrings */
47 gs_ptr_type_t
enum_bytestring(enum_ptr_t * pep,const gs_bytestring * pbs)48 enum_bytestring(enum_ptr_t *pep, const gs_bytestring *pbs)
49 {
50     return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_STRING(pbs));
51 }
52 gs_ptr_type_t
enum_const_bytestring(enum_ptr_t * pep,const gs_const_bytestring * pbs)53 enum_const_bytestring(enum_ptr_t *pep, const gs_const_bytestring *pbs)
54 {
55     return (pbs->bytes ? ENUM_OBJ(pbs->bytes) : ENUM_CONST_STRING(pbs));
56 }
57 void
reloc_bytestring(gs_bytestring * pbs,gc_state_t * gcst)58 reloc_bytestring(gs_bytestring *pbs, gc_state_t *gcst)
59 {
60     if (pbs->bytes) {
61         byte *bytes = pbs->bytes;
62         long offset = pbs->data - bytes;
63 
64         pbs->bytes = bytes = RELOC_OBJ(bytes);
65         pbs->data = bytes + offset;
66     } else
67         RELOC_STRING_VAR(*(gs_string *)pbs);
68 }
69 void
reloc_const_bytestring(gs_const_bytestring * pbs,gc_state_t * gcst)70 reloc_const_bytestring(gs_const_bytestring *pbs, gc_state_t *gcst)
71 {
72     if (pbs->bytes) {
73         const byte *bytes = pbs->bytes;
74         long offset = pbs->data - bytes;
75 
76         pbs->bytes = bytes = RELOC_OBJ(bytes);
77         pbs->data = bytes + offset;
78     } else
79         RELOC_CONST_STRING_VAR(*(gs_const_string *)pbs);
80 }
81 
82 /* Fill an unoccupied block with a pattern. */
83 /* Note that the block size may be too large for a single memset. */
84 void
gs_alloc_memset(void * ptr,int fill,ulong lsize)85 gs_alloc_memset(void *ptr, int /*byte */ fill, ulong lsize)
86 {
87     ulong msize = lsize;
88     char *p = ptr;
89     int isize;
90 
91     for (; msize; msize -= isize, p += isize) {
92         isize = min(msize, max_int);
93         memset(p, fill, isize);
94     }
95 }
96 
97 /*
98  * Either allocate (if obj == 0) or resize (if obj != 0) a structure array.
99  * If obj != 0, pstype is used only for checking (in DEBUG configurations).
100  */
101 void *
gs_resize_struct_array(gs_memory_t * mem,void * obj,uint num_elements,gs_memory_type_ptr_t pstype,client_name_t cname)102 gs_resize_struct_array(gs_memory_t *mem, void *obj, uint num_elements,
103                        gs_memory_type_ptr_t pstype, client_name_t cname)
104 {
105     if (obj == 0)
106         return gs_alloc_struct_array(mem, num_elements, void, pstype, cname);
107 #ifdef DEBUG
108     if (gs_object_type(mem, obj) != pstype) {
109         lprintf3("resize_struct_array 0x%lx, type was 0x%lx, expected 0x%lx!\n",
110                  (ulong)obj, (ulong)gs_object_type(mem, obj), (ulong)pstype);
111         return 0;
112     }
113 #endif
114     return gs_resize_object(mem, obj, num_elements, cname);
115 }
116 
117 /* Allocate a structure using a "raw memory" allocator.
118  * really just an alias for gs_alloc_struct_immovable
119  * with the clients false expectation that it is saving memory
120  */
121 
122 void *
gs_raw_alloc_struct_immovable(gs_memory_t * rmem,gs_memory_type_ptr_t pstype,client_name_t cname)123 gs_raw_alloc_struct_immovable(gs_memory_t * rmem,
124                               gs_memory_type_ptr_t pstype,
125                               client_name_t cname)
126 {
127     return gs_alloc_bytes_immovable(rmem, gs_struct_type_size(pstype), cname);
128 }
129 
130 /* No-op freeing procedures */
131 void
gs_ignore_free_object(gs_memory_t * mem,void * data,client_name_t cname)132 gs_ignore_free_object(gs_memory_t * mem, void *data, client_name_t cname)
133 {
134 }
135 void
gs_ignore_free_string(gs_memory_t * mem,byte * data,uint nbytes,client_name_t cname)136 gs_ignore_free_string(gs_memory_t * mem, byte * data, uint nbytes,
137                       client_name_t cname)
138 {
139 }
140 
141 /* Deconstifying freeing procedures. */
142 /* These procedures rely on a severely deprecated pun. */
143 void
gs_free_const_object(gs_memory_t * mem,const void * data,client_name_t cname)144 gs_free_const_object(gs_memory_t * mem, const void *data, client_name_t cname)
145 {
146     union { const void *r; void *w; } u;
147 
148     u.r = data;
149     gs_free_object(mem, u.w, cname);
150 }
151 void
gs_free_const_string(gs_memory_t * mem,const byte * data,uint nbytes,client_name_t cname)152 gs_free_const_string(gs_memory_t * mem, const byte * data, uint nbytes,
153                      client_name_t cname)
154 {
155     union { const byte *r; byte *w; } u;
156 
157     u.r = data;
158     gs_free_string(mem, u.w, nbytes, cname);
159 }
160 
161 /* Free a [const] bytestring. */
162 void
gs_free_bytestring(gs_memory_t * mem,gs_bytestring * pbs,client_name_t cname)163 gs_free_bytestring(gs_memory_t *mem, gs_bytestring *pbs, client_name_t cname)
164 {
165     if (pbs->bytes)
166         gs_free_object(mem, pbs->bytes, cname);
167     else
168         gs_free_string(mem, pbs->data, pbs->size, cname);
169 }
170 void
gs_free_const_bytestring(gs_memory_t * mem,gs_const_bytestring * pbs,client_name_t cname)171 gs_free_const_bytestring(gs_memory_t *mem, gs_const_bytestring *pbs,
172                          client_name_t cname)
173 {
174     if (pbs->bytes)
175         gs_free_const_object(mem, pbs->bytes, cname);
176     else
177         gs_free_const_string(mem, pbs->data, pbs->size, cname);
178 }
179 
180 /* No-op consolidation procedure */
181 void
gs_ignore_consolidate_free(gs_memory_t * mem)182 gs_ignore_consolidate_free(gs_memory_t *mem)
183 {
184 }
185 
186 /* No-op pointer enumeration procedure */
ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)187 ENUM_PTRS_BEGIN_PROC(gs_no_struct_enum_ptrs)
188 {
189     return 0;
190     ENUM_PTRS_END_PROC
191 }
192 
193 /* No-op pointer relocation procedure */
RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)194 RELOC_PTRS_BEGIN(gs_no_struct_reloc_ptrs)
195 {
196 }
197 RELOC_PTRS_END
198 
199 /* Get the size of a structure from the descriptor. */
200 uint
gs_struct_type_size(gs_memory_type_ptr_t pstype)201 gs_struct_type_size(gs_memory_type_ptr_t pstype)
202 {
203     return pstype->ssize;
204 }
205 
206 /* Get the name of a structure from the descriptor. */
207 struct_name_t
gs_struct_type_name(gs_memory_type_ptr_t pstype)208 gs_struct_type_name(gs_memory_type_ptr_t pstype)
209 {
210     return pstype->sname;
211 }
212 
213 /* Register a structure root. */
214 int
gs_register_struct_root(gs_memory_t * mem,gs_gc_root_t * root,void ** pp,client_name_t cname)215 gs_register_struct_root(gs_memory_t *mem, gs_gc_root_t *root,
216                         void **pp, client_name_t cname)
217 {
218     return gs_register_root(mem, root, ptr_struct_type, pp, cname);
219 }
220 
221 /* ---------------- Reference counting ---------------- */
222 
223 #ifdef DEBUG
224 
225 static const char *
rc_object_type_name(const void * vp,const rc_header * prc)226 rc_object_type_name(const void *vp, const rc_header *prc)
227 {
228     gs_memory_type_ptr_t pstype;
229 
230     if (prc->memory == 0)
231         return "(unknown)";
232     pstype = gs_object_type(prc->memory, vp);
233     if (prc->free != rc_free_struct_only) {
234         /*
235          * This object might be stack-allocated or have other unusual memory
236          * management properties.  Make some reasonableness checks.
237          * ****** THIS IS A HACK. ******
238          */
239         long dist;
240 
241         dist = (const char *)&dist - (const char *)vp;
242         if (dist < 10000 && dist > -10000)
243             return "(on stack)";
244         if ((ulong)pstype < 0x10000 || (long)pstype < 0)
245             return "(anomalous)";
246     }
247     return client_name_string(gs_struct_type_name(pstype));
248 }
249 
250 /* Trace reference count operations. */
251 void
rc_trace_init_free(const void * vp,const rc_header * prc)252 rc_trace_init_free(const void *vp, const rc_header *prc)
253 {
254     dprintf3("[^]%s 0x%lx init = %ld\n",
255              rc_object_type_name(vp, prc), (ulong)vp, (long)prc->ref_count);
256 }
257 void
rc_trace_free_struct(const void * vp,const rc_header * prc,client_name_t cname)258 rc_trace_free_struct(const void *vp, const rc_header *prc, client_name_t cname)
259 {
260     dprintf3("[^]%s 0x%lx => free (%s)\n",
261               rc_object_type_name(vp, prc),
262               (ulong)vp, client_name_string(cname));
263 }
264 void
rc_trace_increment(const void * vp,const rc_header * prc)265 rc_trace_increment(const void *vp, const rc_header *prc)
266 {
267     dprintf3("[^]%s 0x%lx ++ => %ld\n",
268               rc_object_type_name(vp, prc),
269               (ulong)vp, (long)prc->ref_count);
270 }
271 void
rc_trace_adjust(const void * vp,const rc_header * prc,int delta)272 rc_trace_adjust(const void *vp, const rc_header *prc, int delta)
273 {
274     dprintf4("[^]%s 0x%lx %+d => %ld\n",
275              rc_object_type_name(vp, prc),
276              (ulong)vp, delta, (long)(prc->ref_count + delta));
277 }
278 
279 #endif /* DEBUG */
280 
281 /* Normal freeing routine for reference-counted structures. */
282 void
rc_free_struct_only(gs_memory_t * mem,void * data,client_name_t cname)283 rc_free_struct_only(gs_memory_t * mem, void *data, client_name_t cname)
284 {
285     if (mem != 0)
286         gs_free_object(mem, data, cname);
287 }
288 
289 /* ---------------- Basic-structure GC procedures ---------------- */
290 
291 /* Enumerate pointers */
ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)292 ENUM_PTRS_BEGIN_PROC(basic_enum_ptrs)
293 {
294     const gc_struct_data_t *psd = pstype->proc_data;
295 
296     /* This check is primarily for misuse of the alloc_struct_array */
297     /* with number of elements 0 and allocation not passing 'element' */
298     if (size == 0) {
299 #ifdef DEBUG
300         dprintf2("  basic_enum_ptrs: Attempt to enum 0 size structure at 0x%lx, type: %s\n",
301                  (ulong)vptr, pstype->sname);
302 #endif
303         return 0;
304     }
305     if (index < psd->num_ptrs) {
306         const gc_ptr_element_t *ppe = &psd->ptrs[index];
307         EV_CONST char *pptr = (EV_CONST char *)vptr + ppe->offset;
308 
309 #ifdef DEBUG
310         /* some extra checking to make sure we aren't out of bounds */
311         if (ppe->offset > size - sizeof(void *)) {
312             dprintf4("  basic_enum_ptrs: Attempt to enum ptr with offset=%d beyond size=%d: structure at 0x%lx, type: %s\n",
313                      ppe->offset, size, (ulong)vptr, pstype->sname);
314             return 0;
315         }
316 #endif
317         switch ((gc_ptr_type_index_t)ppe->type) {
318             case GC_ELT_OBJ:
319                 return ENUM_OBJ(*(const void *EV_CONST *)pptr);
320             case GC_ELT_STRING:
321                 return ENUM_STRING((const gs_string *)pptr);
322             case GC_ELT_CONST_STRING:
323                 return ENUM_CONST_STRING((const gs_const_string *)pptr);
324         }
325     }
326     if (!psd->super_type)
327         return 0;
328     return ENUM_USING(*(psd->super_type),
329                       (EV_CONST void *)
330                         ((EV_CONST char *)vptr + psd->super_offset),
331                       pstype->ssize, index - psd->num_ptrs);
332 }
333 ENUM_PTRS_END_PROC
334 
335 /* Relocate pointers */
RELOC_PTRS_BEGIN(basic_reloc_ptrs)336 RELOC_PTRS_BEGIN(basic_reloc_ptrs)
337 {
338     const gc_struct_data_t *psd = pstype->proc_data;
339     uint i;
340 
341     for (i = 0; i < psd->num_ptrs; ++i) {
342         const gc_ptr_element_t *ppe = &psd->ptrs[i];
343         char *pptr = (char *)vptr + ppe->offset;
344 
345         switch ((gc_ptr_type_index_t) ppe->type) {
346             case GC_ELT_OBJ:
347                 RELOC_OBJ_VAR(*(void **)pptr);
348                 break;
349             case GC_ELT_STRING:
350                 RELOC_STRING_VAR(*(gs_string *)pptr);
351                 break;
352             case GC_ELT_CONST_STRING:
353                 RELOC_CONST_STRING_VAR(*(gs_const_string *)pptr);
354                 break;
355         }
356     }
357     if (psd->super_type)
358         RELOC_USING(*(psd->super_type),
359                       (void *)((char *)vptr + psd->super_offset),
360                       pstype->ssize);
361 } RELOC_PTRS_END
362