[gs-cvs] rev 8219 - trunk/gs/src
leonardo at ghostscript.com
leonardo at ghostscript.com
Thu Aug 30 21:47:58 PDT 2007
Author: leonardo
Date: 2007-08-30 21:47:58 -0700 (Thu, 30 Aug 2007)
New Revision: 8219
Modified:
trunk/gs/src/gxccache.c
trunk/gs/src/gxccman.c
trunk/gs/src/gxchar.c
trunk/gs/src/gxchar.h
Log:
Fix (font rendering) : alloc_char_bits could fall into infinite loop.
DETAILS :
Bug 689036 "infinite loop in char cache logic".
The character cache algorithm assumes that a pointer to
any allocated cached_char instance appears somewhere in ccache.table .
However from the old experience we know that
this obvious invariant appears frequently broken due
to inaccurate manipulation with cache by clients.
For example, a client sometimes reserves and initializes
a cached_char instance and then fail due to another error
before storing the pointer to ccache.table.
In the old code a cycle in alloc_char_bits
strongly depends on this invariant,
and therefore it is potentially harmful.
In the past we have got a lot of bugs about it.
Now we restrict the cycle with the cache size.
Changed few function prototypes with returning error
if the invariant is broken.
Note that the graphics library interface changes,
so other interpreters must update the calls to
alloc_char_bits.
EXPECTED DIFFERENCES :
None.
Modified: trunk/gs/src/gxccache.c
===================================================================
--- trunk/gs/src/gxccache.c 2007-08-30 05:53:42 UTC (rev 8218)
+++ trunk/gs/src/gxccache.c 2007-08-31 04:47:58 UTC (rev 8219)
@@ -223,9 +223,11 @@
return 0;
}
log2_scale.x = log2_scale.y = 1;
- cc = gx_alloc_char_bits(font->dir, NULL, NULL,
+ code = gx_alloc_char_bits(font->dir, NULL, NULL,
(ushort)(bbox.q.x - bbox.p.x), (ushort)(bbox.q.y - bbox.p.y),
- &log2_scale, 1);
+ &log2_scale, 1, &cc);
+ if (code < 0)
+ return code;
if (cc == 0)
return 0;
/* Success. Make the cache entry. */
Modified: trunk/gs/src/gxccman.c
===================================================================
--- trunk/gs/src/gxccman.c 2007-08-30 05:53:42 UTC (rev 8218)
+++ trunk/gs/src/gxccman.c 2007-08-31 04:47:58 UTC (rev 8219)
@@ -58,8 +58,8 @@
/* Forward references */
private gx_xfont * lookup_xfont_by_name(gx_device *, const gx_xfont_procs *, gs_font_name *, int, const cached_fm_pair *, const gs_matrix *);
-private cached_char *alloc_char(gs_font_dir *, ulong);
-private cached_char *alloc_char_in_chunk(gs_font_dir *, ulong);
+private int alloc_char(gs_font_dir *, ulong, cached_char **);
+private int alloc_char_in_chunk(gs_font_dir *, ulong, cached_char **);
private void hash_remove_cached_char(gs_font_dir *, uint);
private void shorten_cached_char(gs_font_dir *, cached_char *, uint);
@@ -553,10 +553,10 @@
* not NULL, dev should be an alpha-buffer device with dev2 (an alpha
* device) as target.
*/
-cached_char *
+int
gx_alloc_char_bits(gs_font_dir * dir, gx_device_memory * dev,
gx_device_memory * dev2, ushort iwidth, ushort iheight,
- const gs_log2_scale_point * pscale, int depth)
+ const gs_log2_scale_point * pscale, int depth, cached_char **pcc)
{
int log2_xscale = pscale->x;
int log2_yscale = pscale->y;
@@ -569,7 +569,9 @@
gx_device_memory *pdev = dev;
gx_device_memory *pdev2;
float HWResolution0 = 72, HWResolution1 = 72; /* default for dev == NULL */
+ int code;
+ *pcc = 0;
if (dev == NULL) {
mdev.memory = 0;
mdev.target = 0;
@@ -637,7 +639,10 @@
dev->HWResolution[1] = HWResolution1 * (1 >> log2_yscale);
}
icdsize = isize + sizeof_cached_char;
- cc = alloc_char(dir, icdsize);
+ code = alloc_char(dir, icdsize, &cc);
+ if (code < 0)
+ return code;
+ *pcc = cc;
if (cc == 0)
return 0;
if_debug4('k', "[k]adding char 0x%lx:%u(%u,%u)\n",
@@ -675,7 +680,7 @@
} else if (dev)
gx_open_cache_device(dev, cc);
- return cc;
+ return 0;
}
/* Open the cache device. */
@@ -962,11 +967,15 @@
/* ------ Internal routines ------ */
/* Allocate data space for a cached character, adding a new chunk if needed. */
-private cached_char *
-alloc_char(gs_font_dir * dir, ulong icdsize)
+private int
+alloc_char(gs_font_dir * dir, ulong icdsize, cached_char **pcc)
{ /* Try allocating at the current position first. */
- cached_char *cc = alloc_char_in_chunk(dir, icdsize);
+ cached_char *cc;
+ int code = alloc_char_in_chunk(dir, icdsize, &cc);
+ *pcc = cc;
+ if (code < 0)
+ return code;
if (cc == 0) {
if (dir->ccache.bspace < dir->ccache.bmax) { /* Allocate another chunk. */
gs_memory_t *mem = dir->ccache.bits_memory;
@@ -1008,26 +1017,34 @@
while ((dir->ccache.chunks = cck = cck->next) != cck_init) {
dir->ccache.cnext = 0;
- cc = alloc_char_in_chunk(dir, icdsize);
- if (cc != 0)
- return cc;
+ code = alloc_char_in_chunk(dir, icdsize, &cc);
+ if (code < 0)
+ return code;
+ if (cc != 0) {
+ *pcc = cc;
+ return 0;
+ }
}
}
dir->ccache.cnext = 0;
- cc = alloc_char_in_chunk(dir, icdsize);
+ code = alloc_char_in_chunk(dir, icdsize, &cc);
+ if (code < 0)
+ return code;
+ *pcc = cc;
}
- return cc;
+ return 0;
}
/* Allocate a character in the current chunk. */
-private cached_char *
-alloc_char_in_chunk(gs_font_dir * dir, ulong icdsize)
+private int
+alloc_char_in_chunk(gs_font_dir * dir, ulong icdsize, cached_char **pcc)
{
char_cache_chunk *cck = dir->ccache.chunks;
cached_char_head *cch;
#define cc ((cached_char *)cch)
+ *pcc = 0;
while (gx_bits_cache_alloc((gx_bits_cache *) & dir->ccache,
icdsize, &cch) < 0
) {
@@ -1045,9 +1062,13 @@
if (pair != 0) {
uint chi = chars_head_index(cc->code, pair);
+ uint cnt = dir->ccache.table_mask + 1;
- while (dir->ccache.table[chi & dir->ccache.table_mask] != cc)
+ while (dir->ccache.table[chi & dir->ccache.table_mask] != cc) {
chi++;
+ if (cnt-- == 0)
+ return_error(gs_error_unregistered); /* Must not happen. */
+ }
hash_remove_cached_char(dir, chi);
}
@@ -1061,7 +1082,8 @@
cc->chunk = cck;
cc->loc = (byte *) cc - cck->data;
- return cc;
+ *pcc = cc;
+ return 0;
#undef cc
}
Modified: trunk/gs/src/gxchar.c
===================================================================
--- trunk/gs/src/gxchar.c 2007-08-30 05:53:42 UTC (rev 8218)
+++ trunk/gs/src/gxchar.c 2007-08-31 04:47:58 UTC (rev 8219)
@@ -624,11 +624,11 @@
* from oversampled bitmap strips to alpha values instead of
* full oversampling with compression at the end.
*/
- cc = gx_alloc_char_bits(dir, penum->dev_cache,
+ code = gx_alloc_char_bits(dir, penum->dev_cache,
(iwidth > MAX_TEMP_BITMAP_BITS / iheight &&
log2_scale.x + log2_scale.y > alpha_bits ?
penum->dev_cache2 : NULL),
- iwidth, iheight, &log2_scale, depth);
+ iwidth, iheight, &log2_scale, depth, &cc);
if (cc == 0) {
/* too big for cache or no cache */
gx_path box_path;
Modified: trunk/gs/src/gxchar.h
===================================================================
--- trunk/gs/src/gxchar.h 2007-08-30 05:53:42 UTC (rev 8218)
+++ trunk/gs/src/gxchar.h 2007-08-31 04:47:58 UTC (rev 8219)
@@ -119,8 +119,7 @@
typedef struct gs_font_dir_s gs_font_dir;
#endif
-cached_char *
- gx_alloc_char_bits(gs_font_dir *, gx_device_memory *, gx_device_memory *, ushort, ushort, const gs_log2_scale_point *, int);
+int gx_alloc_char_bits(gs_font_dir *, gx_device_memory *, gx_device_memory *, ushort, ushort, const gs_log2_scale_point *, int, cached_char **);
void gx_open_cache_device(gx_device_memory *, cached_char *);
void gx_free_cached_char(gs_font_dir *, cached_char *);
int gx_add_cached_char(gs_font_dir *, gx_device_memory *, cached_char *, cached_fm_pair *, const gs_log2_scale_point *);
More information about the gs-cvs
mailing list