1 /* Copyright (C) 2001-2019 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., 1305 Grant Avenue - Suite 200, Novato,
13 CA 94945, U.S.A., +1(415)492-9861, for further information.
14 */
15
16
17 /* "Virtual memory" operators */
18 #include "stat_.h" /* get system header early to avoid name clash on Cygwin */
19 #include "ghost.h"
20 #include "gsstruct.h"
21 #include "oper.h"
22 #include "estack.h" /* for checking in restore */
23 #include "ialloc.h"
24 #include "idict.h" /* ditto */
25 #include "igstate.h"
26 #include "isave.h"
27 #include "dstack.h"
28 #include "stream.h" /* for files.h */
29 #include "files.h" /* for e-stack processing */
30 #include "store.h"
31 #include "gsmatrix.h" /* for gsstate.h */
32 #include "gsstate.h"
33
34 /* Define whether we validate memory before/after save/restore. */
35 /* Note that we only actually do this if DEBUG is set and -Z? is selected. */
36 static const bool I_VALIDATE_BEFORE_SAVE = true;
37 static const bool I_VALIDATE_AFTER_SAVE = true;
38 static const bool I_VALIDATE_BEFORE_RESTORE = true;
39 static const bool I_VALIDATE_AFTER_RESTORE = true;
40
41 gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
42 vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
43
44 /* Clean up the stacks and validate storage. */
45 void
ivalidate_clean_spaces(i_ctx_t * i_ctx_p)46 ivalidate_clean_spaces(i_ctx_t *i_ctx_p)
47 {
48 if (gs_debug_c('?')) {
49 ref_stack_cleanup(&d_stack);
50 ref_stack_cleanup(&e_stack);
51 ref_stack_cleanup(&o_stack);
52 ivalidate_spaces();
53 }
54 }
55
56 /* - save <save> */
57 int
zsave(i_ctx_t * i_ctx_p)58 zsave(i_ctx_t *i_ctx_p)
59 {
60 os_ptr op = osp;
61 uint space = icurrent_space;
62 vm_save_t *vmsave;
63 ulong sid;
64 int code;
65 gs_gstate *prev;
66
67 if (I_VALIDATE_BEFORE_SAVE)
68 ivalidate_clean_spaces(i_ctx_p);
69 ialloc_set_space(idmemory, avm_local);
70 vmsave = ialloc_struct(vm_save_t, &st_vm_save, "zsave");
71 ialloc_set_space(idmemory, space);
72 if (vmsave == 0)
73 return_error(gs_error_VMerror);
74 vmsave->gsave = NULL; /* Ensure constructed enough to destroy safely */
75 code = alloc_save_state(idmemory, vmsave, &sid);
76 if (code < 0)
77 return code;
78 if (sid == 0) {
79 ifree_object(vmsave, "zsave");
80 return_error(gs_error_VMerror);
81 }
82 if_debug2m('u', imemory, "[u]vmsave 0x%lx, id = %lu\n",
83 (ulong) vmsave, (ulong) sid);
84 code = gs_gsave_for_save(igs, &prev);
85 if (code < 0)
86 return code;
87 vmsave->gsave = prev;
88 push(1);
89 make_tav(op, t_save, 0, saveid, sid);
90 if (I_VALIDATE_AFTER_SAVE)
91 ivalidate_clean_spaces(i_ctx_p);
92 return 0;
93 }
94
95 /* <save> restore - */
96 static int restore_check_operand(os_ptr, alloc_save_t **, gs_dual_memory_t *);
97 static int restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t *, const alloc_save_t *, bool);
98 static void restore_fix_stack(i_ctx_t *i_ctx_p, ref_stack_t *, const alloc_save_t *, bool);
99
100 /* Do as many up front checks of the save object as we reasonably can */
101 int
restore_check_save(i_ctx_t * i_ctx_p,alloc_save_t ** asave)102 restore_check_save(i_ctx_t *i_ctx_p, alloc_save_t **asave)
103 {
104 os_ptr op = osp;
105 int code = restore_check_operand(op, asave, idmemory);
106
107 if (code < 0)
108 return code;
109 if_debug2m('u', imemory, "[u]vmrestore 0x%lx, id = %lu\n",
110 (ulong) alloc_save_client_data(*asave),
111 (ulong) op->value.saveid);
112 if (I_VALIDATE_BEFORE_RESTORE)
113 ivalidate_clean_spaces(i_ctx_p);
114 /* Check the contents of the stacks. */
115 osp--;
116 {
117 int code;
118
119 if ((code = restore_check_stack(i_ctx_p, &o_stack, *asave, false)) < 0 ||
120 (code = restore_check_stack(i_ctx_p, &e_stack, *asave, true)) < 0 ||
121 (code = restore_check_stack(i_ctx_p, &d_stack, *asave, false)) < 0
122 ) {
123 osp++;
124 return code;
125 }
126 }
127 osp++;
128 return 0;
129 }
130
131 /* the semantics of restore differ slightly between Level 1 and
132 Level 2 and later - the latter includes restoring the device
133 state (whilst Level 1 didn't have "page devices" as such).
134 Hence we have two restore operators - one here (Level 1)
135 and one in zdevice2.c (Level 2+). For that reason, the
136 operand checking and guts of the restore operation are
137 separated so both implementations can use them to best
138 effect.
139 */
140 int
dorestore(i_ctx_t * i_ctx_p,alloc_save_t * asave)141 dorestore(i_ctx_t *i_ctx_p, alloc_save_t *asave)
142 {
143 bool last;
144 vm_save_t *vmsave;
145 int code;
146
147 osp--;
148
149 /* Reset l_new in all stack entries if the new save level is zero. */
150 /* Also do some special fixing on the e-stack. */
151 restore_fix_stack(i_ctx_p, &o_stack, asave, false);
152 restore_fix_stack(i_ctx_p, &e_stack, asave, true);
153 restore_fix_stack(i_ctx_p, &d_stack, asave, false);
154 /* Iteratively restore the state of memory, */
155 /* also doing a grestoreall at each step. */
156 do {
157 vmsave = alloc_save_client_data(alloc_save_current(idmemory));
158 /* Restore the graphics state. */
159 gs_grestoreall_for_restore(igs, vmsave->gsave);
160 /*
161 * If alloc_save_space decided to do a second save, the vmsave
162 * object was allocated one save level less deep than the
163 * current level, so ifree_object won't actually free it;
164 * however, it points to a gsave object that definitely
165 * *has* been freed. In order not to trip up the garbage
166 * collector, we clear the gsave pointer now.
167 */
168 vmsave->gsave = 0;
169 /* Now it's safe to restore the state of memory. */
170 code = alloc_restore_step_in(idmemory, asave);
171 if (code < 0)
172 return code;
173 last = code;
174 }
175 while (!last);
176 {
177 uint space = icurrent_space;
178
179 ialloc_set_space(idmemory, avm_local);
180 ifree_object(vmsave, "zrestore");
181 ialloc_set_space(idmemory, space);
182 }
183 dict_set_top(); /* reload dict stack cache */
184 if (I_VALIDATE_AFTER_RESTORE)
185 ivalidate_clean_spaces(i_ctx_p);
186 /* If the i_ctx_p LockFilePermissions is true, but the userparams */
187 /* we just restored is false, we need to make sure that we do not */
188 /* cause an 'invalidaccess' in setuserparams. Temporarily set */
189 /* LockFilePermissions false until the gs_lev2.ps can do a */
190 /* setuserparams from the restored userparam dictionary. */
191 /* NOTE: This is safe to do here, since the restore has */
192 /* successfully completed - this should never come before any */
193 /* operation that can trigger an error */
194 i_ctx_p->LockFilePermissions = false;
195 return 0;
196 }
197
198 int
zrestore(i_ctx_t * i_ctx_p)199 zrestore(i_ctx_t *i_ctx_p)
200 {
201 alloc_save_t *asave;
202 int code = restore_check_save(i_ctx_p, &asave);
203 if (code < 0)
204 return code;
205
206 return dorestore(i_ctx_p, asave);
207 }
208
209 /* Check the operand of a restore. */
210 static int
restore_check_operand(os_ptr op,alloc_save_t ** pasave,gs_dual_memory_t * idmem)211 restore_check_operand(os_ptr op, alloc_save_t ** pasave,
212 gs_dual_memory_t *idmem)
213 {
214 vm_save_t *vmsave;
215 ulong sid;
216 alloc_save_t *asave;
217
218 check_type(*op, t_save);
219 vmsave = r_ptr(op, vm_save_t);
220 if (vmsave == 0) /* invalidated save */
221 return_error(gs_error_invalidrestore);
222 sid = op->value.saveid;
223 asave = alloc_find_save(idmem, sid);
224 if (asave == 0)
225 return_error(gs_error_invalidrestore);
226 *pasave = asave;
227 return 0;
228 }
229
230 /* Check a stack to make sure all its elements are older than a save. */
231 static int
restore_check_stack(const i_ctx_t * i_ctx_p,const ref_stack_t * pstack,const alloc_save_t * asave,bool is_estack)232 restore_check_stack(const i_ctx_t *i_ctx_p, const ref_stack_t * pstack,
233 const alloc_save_t * asave, bool is_estack)
234 {
235 ref_stack_enum_t rsenum;
236
237 ref_stack_enum_begin(&rsenum, pstack);
238 do {
239 const ref *stkp = rsenum.ptr;
240 uint size = rsenum.size;
241
242 for (; size; stkp++, size--) {
243 const void *ptr;
244
245 switch (r_type(stkp)) {
246 case t_array:
247 /*
248 * Zero-length arrays are a special case: see the
249 * t_*array case (label rr:) in igc.c:gc_trace.
250 */
251 if (r_size(stkp) == 0) {
252 /*stkp->value.refs = (void *)0;*/
253 continue;
254 }
255 ptr = stkp->value.refs;
256 break;
257 case t_dictionary:
258 ptr = stkp->value.pdict;
259 break;
260 case t_file:
261 /* Don't check executable or closed literal */
262 /* files on the e-stack. */
263 {
264 stream *s;
265
266 if (is_estack &&
267 (r_has_attr(stkp, a_executable) ||
268 file_is_invalid(s, stkp))
269 )
270 continue;
271 }
272 ptr = stkp->value.pfile;
273 break;
274 case t_name:
275 /* Names are special because of how they are allocated. */
276 if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory,
277 stkp, asave))
278 return_error(gs_error_invalidrestore);
279 continue;
280 case t_string:
281 /* Don't check empty executable strings */
282 /* on the e-stack. */
283 if (r_size(stkp) == 0 &&
284 r_has_attr(stkp, a_executable) && is_estack
285 )
286 continue;
287 ptr = stkp->value.bytes;
288 break;
289 case t_mixedarray:
290 case t_shortarray:
291 /* See the t_array case above. */
292 if (r_size(stkp) == 0) {
293 /*stkp->value.packed = (void *)0;*/
294 continue;
295 }
296 ptr = stkp->value.packed;
297 break;
298 case t_device:
299 ptr = stkp->value.pdevice;
300 break;
301 case t_fontID:
302 case t_struct:
303 case t_astruct:
304 ptr = stkp->value.pstruct;
305 break;
306 case t_save:
307 /* See the comment in isave.h regarding the following. */
308 if (i_ctx_p->language_level <= 2)
309 continue;
310 ptr = alloc_find_save(&gs_imemory, stkp->value.saveid);
311 /*
312 * Invalid save objects aren't supposed to be possible
313 * in LL3, but just in case....
314 */
315 if (ptr == 0)
316 return_error(gs_error_invalidrestore);
317 if (ptr == asave)
318 continue;
319 break;
320 default:
321 continue;
322 }
323 if (alloc_is_since_save(ptr, asave))
324 return_error(gs_error_invalidrestore);
325 }
326 } while (ref_stack_enum_next(&rsenum));
327 return 0; /* OK */
328 }
329 /*
330 * If the new save level is zero, fix up the contents of a stack
331 * by clearing the l_new bit in all the entries (since we can't tolerate
332 * values with l_new set if the save level is zero).
333 * Also, in any case, fix up the e-stack by replacing empty executable
334 * strings and closed executable files that are newer than the save
335 * with canonical ones that aren't.
336 *
337 * Note that this procedure is only called if restore_check_stack succeeded.
338 */
339 static void
restore_fix_stack(i_ctx_t * i_ctx_p,ref_stack_t * pstack,const alloc_save_t * asave,bool is_estack)340 restore_fix_stack(i_ctx_t *i_ctx_p, ref_stack_t * pstack,
341 const alloc_save_t * asave, bool is_estack)
342 {
343 ref_stack_enum_t rsenum;
344
345 ref_stack_enum_begin(&rsenum, pstack);
346 do {
347 ref *stkp = rsenum.ptr;
348 uint size = rsenum.size;
349
350 for (; size; stkp++, size--) {
351 r_clear_attrs(stkp, l_new); /* always do it, no harm */
352 if (is_estack) {
353 ref ofile;
354
355 ref_assign(&ofile, stkp);
356 switch (r_type(stkp)) {
357 case t_string:
358 if (r_size(stkp) == 0 &&
359 alloc_is_since_save(stkp->value.bytes,
360 asave)
361 ) {
362 make_empty_const_string(stkp,
363 avm_foreign);
364 break;
365 }
366 continue;
367 case t_file:
368 if (alloc_is_since_save(stkp->value.pfile,
369 asave)
370 ) {
371 make_invalid_file(i_ctx_p, stkp);
372 break;
373 }
374 continue;
375 default:
376 continue;
377 }
378 r_copy_attrs(stkp, a_all | a_executable,
379 &ofile);
380 }
381 }
382 } while (ref_stack_enum_next(&rsenum));
383 }
384
385 /* - vmstatus <save_level> <vm_used> <vm_maximum> */
386 static int
zvmstatus(i_ctx_t * i_ctx_p)387 zvmstatus(i_ctx_t *i_ctx_p)
388 {
389 os_ptr op = osp;
390 gs_memory_status_t mstat, dstat;
391
392 gs_memory_status(imemory, &mstat);
393 if (imemory == imemory_global) {
394 gs_memory_status_t sstat;
395
396 gs_memory_status(imemory_system, &sstat);
397 mstat.allocated += sstat.allocated;
398 mstat.used += sstat.used;
399 }
400 gs_memory_status(imemory->non_gc_memory, &dstat);
401 push(3);
402 make_int(op - 2, imemory_save_level(iimemory_local));
403 make_int(op - 1, mstat.used);
404 make_int(op, mstat.allocated + dstat.allocated - dstat.used);
405 return 0;
406 }
407
408 /* ------ Non-standard extensions ------ */
409
410 /* <save> .forgetsave - */
411 static int
zforgetsave(i_ctx_t * i_ctx_p)412 zforgetsave(i_ctx_t *i_ctx_p)
413 {
414 os_ptr op = osp;
415 alloc_save_t *asave;
416 vm_save_t *vmsave;
417 int code = restore_check_operand(op, &asave, idmemory);
418
419 if (code < 0)
420 return 0;
421 vmsave = alloc_save_client_data(asave);
422 /* Reset l_new in all stack entries if the new save level is zero. */
423 restore_fix_stack(i_ctx_p, &o_stack, asave, false);
424 restore_fix_stack(i_ctx_p, &e_stack, asave, false);
425 restore_fix_stack(i_ctx_p, &d_stack, asave, false);
426 /*
427 * Forget the gsaves, by deleting the bottom gstate on
428 * the current stack and the top one on the saved stack and then
429 * concatenating the stacks together.
430 */
431 {
432 gs_gstate *pgs = igs;
433 gs_gstate *last;
434
435 while (gs_gstate_saved(last = gs_gstate_saved(pgs)) != 0)
436 pgs = last;
437 gs_gstate_swap_saved(last, vmsave->gsave);
438 gs_grestore(last);
439 gs_grestore(last);
440 }
441 /* Forget the save in the memory manager. */
442 code = alloc_forget_save_in(idmemory, asave);
443 if (code < 0)
444 return code;
445 {
446 uint space = icurrent_space;
447
448 ialloc_set_space(idmemory, avm_local);
449 /* See above for why we clear the gsave pointer here. */
450 vmsave->gsave = 0;
451 ifree_object(vmsave, "zrestore");
452 ialloc_set_space(idmemory, space);
453 }
454 pop(1);
455 return 0;
456 }
457
458 /* ------ Initialization procedure ------ */
459
460 const op_def zvmem_op_defs[] =
461 {
462 {"1.forgetsave", zforgetsave},
463 {"1restore", zrestore},
464 {"0save", zsave},
465 {"0vmstatus", zvmstatus},
466 op_def_end(0)
467 };
468