summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Liddell <chris.liddell@artifex.com>2021-04-08 15:30:56 +0100
committerChris Liddell <chris.liddell@artifex.com>2021-04-09 07:54:56 +0100
commitca567f59767d633eda63e418e4eac680e16c5331 (patch)
treee55a9fc8952f03c089a9562211dd9cdf7051a44b
parent7a708a373809849e2379121218ef3114cdff002d (diff)
downloadghostpdl-ca567f59767d633eda63e418e4eac680e16c5331.tar.gz
Harden the use of the ICC cs cache for Cal spaces
Originally, the cache key used was the "saveid" entry in the ref "value" union. Since the ref object in question was a dictionary, this meant an unsigned long interpretation of the pointer value from "dictval" in the same union. This was unsafe for a couple of reasons: Postscript allows dictionary objects to be reused, so it was feasible for the same dictionary object to be used to define two different color spaces, this meaning the cache would retrieve the wrong ICC color space. Secondly, garbage collection results in objects (like dictval instances) moving address. So, the same dictionary need not be at the same address, but a different dictionary could be. Since the other CIE based spaces use an MD5 hash of the contents of the color spaces to create the cache key, this implements the same things, bringing the Cal color spaces in-line with their CIE bretherin. In addition, where we retrieve color spaces from the ICC cs cache, add in a simple validation of the number components before going ahead and using the cached color space. This came out of investigating a *long* standing indeterimate cluster test file tests_private/comparefiles/p2b-100.pdf and we fervently hope that this will fix that indeterminacy.
-rw-r--r--base/gsicc_profilecache.c6
-rw-r--r--psi/zcie.c20
-rw-r--r--psi/zcolor.c145
-rw-r--r--psi/zicc.c6
4 files changed, 169 insertions, 8 deletions
diff --git a/base/gsicc_profilecache.c b/base/gsicc_profilecache.c
index db2e8ae4a..900a3440b 100644
--- a/base/gsicc_profilecache.c
+++ b/base/gsicc_profilecache.c
@@ -95,6 +95,9 @@ gsicc_add_cs(gs_gstate * pgs, gs_color_space * colorspace, uint64_t dictkey)
gsicc_profile_cache_t *profile_cache = pgs->icc_profile_cache;
gs_memory_t *memory = pgs->memory;
+ if (dictkey == 0)
+ return;
+
/* The entry has to be added in stable memory. We want them
to be maintained across the gsave and grestore process */
result = gs_alloc_struct(memory->stable_memory, gsicc_profile_entry_t,
@@ -125,6 +128,9 @@ gsicc_find_cs(uint64_t key_test, gs_gstate * pgs)
gsicc_profile_cache_t *profile_cache = pgs->icc_profile_cache;
gsicc_profile_entry_t *prev = NULL, *curr = profile_cache->head;
+ if (key_test == 0)
+ return NULL;
+
/* Look through the cache for the key. If found, move to MRU */
while (curr != NULL ){
if (curr->key == key_test){
diff --git a/psi/zcie.c b/psi/zcie.c
index 616b4b718..57f92f800 100644
--- a/psi/zcie.c
+++ b/psi/zcie.c
@@ -448,8 +448,11 @@ ciedefgspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
bool has_defg_procs, has_abc_procs, has_lmn_procs;
gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
- if (dictkey != 0)
+ if (dictkey != 0) {
pcs = gsicc_find_cs(dictkey, igs);
+ if (pcs && gs_color_space_num_components(pcs) != 4)
+ pcs = NULL;
+ }
else
pcs = NULL;
push(1); /* Sacrificial */
@@ -558,8 +561,11 @@ ciedefspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
bool has_def_procs, has_lmn_procs, has_abc_procs;
gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
- if (dictkey != 0)
+ if (dictkey != 0) {
pcs = gsicc_find_cs(dictkey, igs);
+ if (pcs && gs_color_space_num_components(pcs) != 3)
+ pcs = NULL;
+ }
else
pcs = NULL;
push(1); /* Sacrificial */
@@ -626,8 +632,11 @@ cieabcspace(i_ctx_t *i_ctx_p, ref *CIEDict, uint64_t dictkey)
gs_ref_memory_t *imem = (gs_ref_memory_t *)mem;
/* See if the color space is in the profile cache */
- if (dictkey != 0)
+ if (dictkey != 0) {
pcs = gsicc_find_cs(dictkey, igs);
+ if (pcs && gs_color_space_num_components(pcs) != 3)
+ pcs = NULL;
+ }
else
pcs = NULL;
@@ -690,8 +699,11 @@ cieaspace(i_ctx_t *i_ctx_p, ref *CIEdict, uint64_t dictkey)
bool has_lmn_procs;
/* See if the color space is in the profile cache */
- if (dictkey != 0)
+ if (dictkey != 0) {
pcs = gsicc_find_cs(dictkey, igs);
+ if (pcs && gs_color_space_num_components(pcs) != 1)
+ pcs = NULL;
+ }
else
pcs = NULL;
push(1); /* Sacrificial */
diff --git a/psi/zcolor.c b/psi/zcolor.c
index 34a9326f3..0b71b934a 100644
--- a/psi/zcolor.c
+++ b/psi/zcolor.c
@@ -5519,6 +5519,60 @@ static int checkGamma(i_ctx_t * i_ctx_p, ref *CIEdict, int numvalues)
return 0;
}
+static int hashcalgrayspace(i_ctx_t *i_ctx_p, ref *space, gs_md5_state_t *md5)
+{
+ int code = 0;
+ ref cgdict1, spacename, *tempref;
+ static const int ncomps = 1;
+ float g = 1.0;
+ int i;
+
+ code = array_get(imemory, space, 0, &spacename);
+ if (code < 0)
+ return 0;
+ gs_md5_append(md5, (const gs_md5_byte_t *)&spacename.value.pname, sizeof(spacename.value.pname));
+
+ code = array_get(imemory, space, 1, &cgdict1);
+ if (code < 0)
+ return 0;
+ check_read_type(cgdict1, t_dictionary);
+
+ code = dict_find_string(&cgdict1, "WhitePoint", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ float WP = 0.0;
+ for (i = 0; i < 3; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&WP, sizeof(WP));
+ }
+ }
+
+ code = dict_find_string(&cgdict1, "BlackPoint", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ float BP = 0.0;
+ for (i = 0; i < 3; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&BP, sizeof(BP));
+ }
+ }
+
+ code = dict_find_string(&cgdict1, "Gamma", &tempref);
+ if (code > 0) {
+ if (r_has_type(tempref, t_real))
+ g = tempref->value.realval;
+ else if (r_has_type(tempref, t_integer))
+ g = (float)tempref->value.intval;
+ }
+
+ gs_md5_append(md5, (const gs_md5_byte_t *)&g, sizeof(g));
+
+ gs_md5_append(md5, (const gs_md5_byte_t *)&ncomps, sizeof(ncomps));
+ return 1;
+}
+
/* Here we set up an equivalent ICC form for the CalGray color space */
static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
{
@@ -5528,6 +5582,9 @@ static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int
double dflt_gamma = 1.0;
static const float dflt_black[3] = {0,0,0}, dflt_white[3] = {0,0,0};
gs_client_color cc;
+ uint64_t dictkey = 0;
+ gs_md5_state_t md5;
+ byte key[16];
*cont = 0;
code = array_get(imemory, r, 1, &graydict);
@@ -5558,8 +5615,15 @@ static int setcalgrayspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int
return code;
if (white[0] <= 0 || white[1] != 1.0 || white[2] <= 0)
return_error(gs_error_rangecheck);
- code = seticc_cal(i_ctx_p, white, black, &gamma, NULL, 1,
- graydict.value.saveid);
+
+ gs_md5_init(&md5);
+ hashcalgrayspace(i_ctx_p, r, &md5);
+ gs_md5_finish(&md5, key);
+ if (code > 0) {
+ dictkey = *(uint64_t *)&key[sizeof(key) - sizeof(uint64_t)];
+ }
+
+ code = seticc_cal(i_ctx_p, white, black, &gamma, NULL, 1, dictkey);
if ( code < 0)
return gs_rethrow(code, "setting CalGray color space");
cc.pattern = 0x00;
@@ -5601,6 +5665,72 @@ static int validatecalgrayspace(i_ctx_t * i_ctx_p, ref **r)
return 0;
}
+static int hashcalrgbspace(i_ctx_t *i_ctx_p, ref *space, gs_md5_state_t *md5)
+{
+ int code = 0;
+ ref crgbdict1, spacename, *tempref;
+ static const int ncomps = 3;
+ int i;
+
+ code = array_get(imemory, space, 0, &spacename);
+ if (code < 0)
+ return 0;
+ gs_md5_append(md5, (const gs_md5_byte_t *)&spacename.value.pname, sizeof(spacename.value.pname));
+
+ code = array_get(imemory, space, 1, &crgbdict1);
+ if (code < 0)
+ return 0;
+ check_read_type(crgbdict1, t_dictionary);
+
+ code = dict_find_string(&crgbdict1, "WhitePoint", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ float WP = 0.0;
+ for (i = 0; i < 3; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&WP, sizeof(WP));
+ }
+ }
+
+ code = dict_find_string(&crgbdict1, "BlackPoint", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ float BP = 0.0;
+ for (i = 0; i < 3; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&BP, sizeof(BP));
+ }
+ }
+
+ code = dict_find_string(&crgbdict1, "Matrix", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ static const float mt[9] = {1,0,0,0,1,0,0,0,1};
+
+ for (i = 0; i < 9; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&(mt[i]), sizeof(mt[i]));
+ }
+ }
+
+ code = dict_find_string(&crgbdict1, "Gamma", &tempref);
+ if (code > 0) {
+ code = hasharray(i_ctx_p, tempref, md5);
+ }
+ if (code <= 0) {
+ static const float g[3] = { 1.0, 1.0, 1.0 };
+ for (i = 0; i < 3; i++) {
+ gs_md5_append(md5, (const gs_md5_byte_t *)&(g[i]), sizeof(g[i]));
+ }
+ }
+
+ gs_md5_append(md5, (const gs_md5_byte_t *)&ncomps, sizeof(ncomps));
+ return 1;
+}
+
/* Here we set up an equivalent ICC form for the CalRGB color space */
static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int CIESubst)
{
@@ -5612,6 +5742,9 @@ static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int
static const float dflt_matrix[9] = {1,0,0,0,1,0,0,0,1};
int i;
gs_client_color cc;
+ uint64_t dictkey = 0;
+ gs_md5_state_t md5;
+ byte key[16];
*cont = 0;
code = array_get(imemory, r, 1, &rgbdict);
@@ -5654,7 +5787,13 @@ static int setcalrgbspace(i_ctx_t * i_ctx_p, ref *r, int *stage, int *cont, int
dflt_matrix );
if (code < 0)
return code;
- code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, rgbdict.value.saveid);
+ gs_md5_init(&md5);
+ hashcalrgbspace(i_ctx_p, r, &md5);
+ gs_md5_finish(&md5, key);
+ if (code > 0) {
+ dictkey = *(uint64_t *)&key[sizeof(key) - sizeof(uint64_t)];
+ }
+ code = seticc_cal(i_ctx_p, white, black, gamma, matrix, 3, dictkey);
if ( code < 0)
return gs_rethrow(code, "setting CalRGB color space");
cc.pattern = 0x00;
diff --git a/psi/zicc.c b/psi/zicc.c
index e01913eb1..91f1c41c9 100644
--- a/psi/zicc.c
+++ b/psi/zicc.c
@@ -64,7 +64,7 @@ int seticc(i_ctx_t * i_ctx_p, int ncomps, ref *ICCdict, float *range_buff)
dict_find_string(ICCdict, ".hash", &phashval) == 1 &&
r_has_type(phashval, t_integer)) {
pcs = gsicc_find_cs(phashval->value.intval, igs);
- if (pcs != NULL) {
+ if (pcs != NULL && gs_color_space_num_components(pcs) == ncomps) {
/* Set the color space. We are done. */
code = gs_setcolorspace(igs, pcs);
/* Remove the ICC dict from the stack */
@@ -468,6 +468,10 @@ seticc_cal(i_ctx_t * i_ctx_p, float *white, float *black, float *gamma,
/* See if the color space is in the profile cache */
pcs = gsicc_find_cs(dictkey, igs);
+ if (pcs != NULL && gs_color_space_num_components(pcs) != num_colorants) {
+ pcs = NULL;
+ dictkey = 0;
+ }
if (pcs == NULL ) {
/* build the color space object. Since this is cached
in the profile cache which is a member variable