/* * If the new save level is zero, fix up the contents of a stack * by clearing the l_new bit in all the entries (since we can't tolerate * values with l_new set if the save level is zero). * Also, in any case, fix up the e-stack by replacing empty executable * strings and closed executable files that are newer than the save * with canonical ones that aren't. * * Note that this procedure is only called if restore_check_stack succeeded. */ static void restore_fix_stack(ref_stack_t * pstack, const alloc_save_t * asave, bool is_estack) { ref_stack_enum_t rsenum; ref_stack_enum_begin(&rsenum, pstack); do { ref *stkp = rsenum.ptr; uint size = rsenum.size; for (; size; stkp++, size--) { r_clear_attrs(stkp, l_new); /* always do it, no harm */ if (is_estack) { ref ofile; ref_assign(&ofile, stkp); switch (r_type(stkp)) { case t_string: if (r_size(stkp) == 0 && alloc_is_since_save(stkp->value.bytes, asave) ) { make_empty_const_string(stkp, avm_foreign); break; } continue; case t_file: if (alloc_is_since_save(stkp->value.pfile, asave) ) { make_invalid_file(stkp); break; } continue; default: continue; } r_copy_attrs(stkp, a_all | a_executable, &ofile); } } } while (ref_stack_enum_next(&rsenum)); }
/* Remove entries from font and character caches. */ int font_restore(const alloc_save_t * save) { gs_memory_t *smem = gs_save_any_memory(save); gs_font_dir *pdir = smem->gs_lib_ctx->font_dir; const gs_memory_t *mem = 0; int code; if (pdir == 0) /* not initialized yet */ return 0; /* Purge original (unscaled) fonts. */ { gs_font *pfont; otop: for (pfont = pdir->orig_fonts; pfont != 0; pfont = pfont->next ) { mem = pfont->memory; if (alloc_is_since_save((char *)pfont, save)) { code = gs_purge_font(pfont); if (code < 0) return code; goto otop; } } } /* Purge cached scaled fonts. */ { gs_font *pfont; top: for (pfont = pdir->scaled_fonts; pfont != 0; pfont = pfont->next ) { if (alloc_is_since_save((char *)pfont, save)) { code = gs_purge_font(pfont); if (code < 0) return code; goto top; } } } /* Purge xfonts and uncached scaled fonts. */ { cached_fm_pair *pair; uint n; for (pair = pdir->fmcache.mdata, n = pdir->fmcache.mmax; n > 0; pair++, n-- ) if (!fm_pair_is_free(pair)) { #if 0 /* We disabled this code portion because gx_add_fm_pair now copied xvalues into a stable memory. */ if ((uid_is_XUID(&pair->UID) && alloc_is_since_save((char *)pair->UID.xvalues, save)) ) { code = gs_purge_fm_pair(pdir, pair, 0); if (code < 0) return code; continue; } #endif if (pair->font != 0 && alloc_is_since_save((char *)pair->font, save) ) { if (!uid_is_valid(&pair->UID)) gs_clean_fm_pair(pdir, pair); /* Don't discard pairs with a surviving UID. */ pair->font = 0; } if (pair->xfont != 0 && alloc_is_since_save((char *)pair->xfont, save) ) { code = gs_purge_fm_pair(pdir, pair, 1); if (code < 0) return code; } } } /* Purge characters with names about to be removed. */ /* We only need to do this if any new names have been created */ /* since the save. */ if (alloc_any_names_since_save(save)) gx_purge_selected_cached_chars(pdir, purge_if_name_removed, (void *)save); return 0; }
/* Check a stack to make sure all its elements are older than a save. */ 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) { ref_stack_enum_t rsenum; ref_stack_enum_begin(&rsenum, pstack); do { const ref *stkp = rsenum.ptr; uint size = rsenum.size; for (; size; stkp++, size--) { const void *ptr; switch (r_type(stkp)) { case t_array: /* * Zero-length arrays are a special case: see the * t_*array case (label rr:) in igc.c:gc_trace. */ if (r_size(stkp) == 0) { /*stkp->value.refs = (void *)0;*/ continue; } ptr = stkp->value.refs; break; case t_dictionary: ptr = stkp->value.pdict; break; case t_file: /* Don't check executable or closed literal */ /* files on the e-stack. */ { stream *s; if (is_estack && (r_has_attr(stkp, a_executable) || file_is_invalid(s, stkp)) ) continue; } ptr = stkp->value.pfile; break; case t_name: /* Names are special because of how they are allocated. */ if (alloc_name_is_since_save((const gs_memory_t *)pstack->memory, stkp, asave)) return_error(e_invalidrestore); continue; case t_string: /* Don't check empty executable strings */ /* on the e-stack. */ if (r_size(stkp) == 0 && r_has_attr(stkp, a_executable) && is_estack ) continue; ptr = stkp->value.bytes; break; case t_mixedarray: case t_shortarray: /* See the t_array case above. */ if (r_size(stkp) == 0) { /*stkp->value.packed = (void *)0;*/ continue; } ptr = stkp->value.packed; break; case t_device: ptr = stkp->value.pdevice; break; case t_fontID: case t_struct: case t_astruct: ptr = stkp->value.pstruct; break; case t_save: /* See the comment in isave.h regarding the following. */ if (i_ctx_p->language_level <= 2) continue; ptr = alloc_find_save(&gs_imemory, stkp->value.saveid); /* * Invalid save objects aren't supposed to be possible * in LL3, but just in case.... */ if (ptr == 0) return_error(e_invalidrestore); if (ptr == asave) continue; break; default: continue; } if (alloc_is_since_save(ptr, asave)) return_error(e_invalidrestore); } } while (ref_stack_enum_next(&rsenum)); return 0; /* OK */ }