From 90e8f8d32b64bae015e19e85e693988daaea54f4 Mon Sep 17 00:00:00 2001 From: Ken Sharp <ken.sharp@artifex.com> Date: Thu, 20 Sep 2018 10:09:37 +0100 Subject: [PATCH] Bug #699796 "copydevice fails after stack device copies invalidated" This isn't anything to do with .fill_identity_cmap. A simpler example is: .distillerdevice nulldevice copydevice The problem is that when we execute nulldevice we need to invalidate any copies, stored on the operand stack, of the device that was current before the nulldevice was installed. We do that by setting the pdevice member of the device structure to NULL. However the fact that a device can be invalidated has clearly passed by a number of developers in the intervening years, and a number of places in the code do check the type of the operand is a device, but they don't check to see if the device has been invalidated. Add validation checks where required. --- psi/idisp.c | 4 ++++ psi/zdevice.c | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/psi/idisp.c b/psi/idisp.c index 2ca7b57..c65671c 100644 --- a/psi/idisp.c +++ b/psi/idisp.c @@ -81,6 +81,10 @@ display_set_callback(gs_main_instance *minst, display_callback *callback) * setting callback, then reopen it. */ check_read_type(op[-1], t_device); + if (op[-1].value.pdevice == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); + dev = op[-1].value.pdevice; was_open = dev->is_open; diff --git a/psi/zdevice.c b/psi/zdevice.c index 7d5f58d..6d2ce05 100644 --- a/psi/zdevice.c +++ b/psi/zdevice.c @@ -46,6 +46,10 @@ zcopydevice2(i_ctx_t *i_ctx_p) check_read_type(op[-1], t_device); check_type(*op, t_boolean); + if (op[-1].value.pdevice == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); + code = gs_copydevice2(&new_dev, op[-1].value.pdevice, op->value.boolval, imemory); if (code < 0) @@ -108,6 +112,10 @@ zdevicename(i_ctx_t *i_ctx_p) const char *dname; check_read_type(*op, t_device); + if (op->value.pdevice == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); + dname = op->value.pdevice->dname; make_const_string(op, avm_foreign | a_readonly, strlen(dname), (const byte *)dname); @@ -157,6 +165,10 @@ zgetbitsrect(i_ctx_t *i_ctx_p) check_read_type(op[-7], t_device); dev = op[-7].value.pdevice; + if (dev == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); + check_int_leu(op[-6], dev->width); rect.p.x = op[-6].value.intval; check_int_leu(op[-5], dev->height); @@ -274,6 +286,9 @@ zget_device_params(i_ctx_t *i_ctx_p, bool is_hardware) } rkeys = *op; dev = op[-1].value.pdevice; + if (op[-1].value.pdevice == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); pop(1); stack_param_list_write(&list, &o_stack, &rkeys, iimemory); code = gs_get_device_or_hardware_params(dev, (gs_param_list *) & list, @@ -440,6 +455,9 @@ zputdeviceparams(i_ctx_t *i_ctx_p) check_type_only(*prequire_all, t_boolean); check_write_type_only(*pdev, t_device); dev = pdev->value.pdevice; + if (dev == NULL) + /* This can happen if we invalidated devices on the stack by calling nulldevice after they were pushed */ + return_error(gs_error_undefined); code = stack_param_list_read(&list, &o_stack, 0, ppolicy, prequire_all->value.boolval, iimemory); if (code < 0) -- 2.9.1