summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-05-25 16:35:19 +0100
committerRobin Watts <robin.watts@artifex.com>2012-05-25 16:35:19 +0100
commit1c9e30044d1d698701091c9913a81e4b3688a134 (patch)
tree7b507cfaaf8223c4636712809aecdffc27e6ecd3
parentc6f9e998b9ab277f85815b927a841c26c507928a (diff)
Add new -debug=validate-chunks debug flag.
This causes a validation to be run after every operator is interpreted. Also, update the chunk validation code to give more informative error messages when problems are found. (For instance, if a reference is found to be duff, it's often the source of that reference you are interested in, not the reference itself).
-rw-r--r--gs/base/gdbflags.h2
-rw-r--r--gs/base/gsmisc.c2
-rw-r--r--gs/psi/ialloc.h2
-rw-r--r--gs/psi/ilocate.c135
-rw-r--r--gs/psi/interp.c4
-rw-r--r--gs/psi/zvmem.c2
6 files changed, 107 insertions, 40 deletions
diff --git a/gs/base/gdbflags.h b/gs/base/gdbflags.h
index 88d7fe2a1..48cf25ad2 100644
--- a/gs/base/gdbflags.h
+++ b/gs/base/gdbflags.h
@@ -21,7 +21,7 @@
UNUSED(0) /* Never use 0, as lots of things 'imply' 0. */
FLAG(icc, 1, 'c', "ICC profile"),
-UNUSED(2)
+FLAG(validate_chunks, 2, 0, "Validate chunks during interpretation"),
UNUSED(3)
UNUSED(4)
UNUSED(5)
diff --git a/gs/base/gsmisc.c b/gs/base/gsmisc.c
index 42f9ff652..292a4c593 100644
--- a/gs/base/gsmisc.c
+++ b/gs/base/gsmisc.c
@@ -1158,7 +1158,7 @@ gs_debug_flags_list(gs_memory_t *heap)
#ifdef DEBUG
int i, j;
- outprintf(heap, "Debugging flags are as follows:\n\n-Z --debug= Description\n");
+ outprintf(heap, "Debugging flags are as follows:\n\n-Z --debug= Description\n");
for (i=0; i < gs_debug_flags_max; i++) {
if (!gs_debug_flags[i].used)
continue;
diff --git a/gs/psi/ialloc.h b/gs/psi/ialloc.h
index 1f0788722..eb9196e61 100644
--- a/gs/psi/ialloc.h
+++ b/gs/psi/ialloc.h
@@ -70,6 +70,8 @@ void ialloc_validate_spaces(const gs_dual_memory_t *);
#define ivalidate_spaces() ialloc_validate_spaces(idmemory)
+void ivalidate_clean_spaces(i_ctx_t *i_ctx_p);
+
/*
* Local/global VM management.
*/
diff --git a/gs/psi/ilocate.c b/gs/psi/ilocate.c
index 5025d81bd..6c6a5f98e 100644
--- a/gs/psi/ilocate.c
+++ b/gs/psi/ilocate.c
@@ -29,6 +29,11 @@
#include "ivmspace.h"
#include "store.h"
+static int do_validate_chunk(const chunk_t * cp, gc_state_t * gcst);
+static int do_validate_object(const obj_header_t * ptr, const chunk_t * cp,
+ gc_state_t * gcst);
+
+
/* ================ Locating ================ */
/* Locate a pointer in the chunks of a space being collected. */
@@ -245,7 +250,11 @@ ialloc_validate_memory(const gs_ref_memory_t * mem, gc_state_t * gcst)
(ulong) mem, mem->space, level);
/* Validate chunks. */
for (cp = smem->cfirst; cp != 0; cp = cp->cnext)
- ialloc_validate_chunk(cp, gcst);
+ if (do_validate_chunk(cp, gcst)) {
+ lprintf3("while validating memory 0x%lx, space %d, level %d\n",
+ (ulong) mem, mem->space, level);
+ gs_abort(gcst->heap);
+ }
/* Validate freelists. */
for (i = 0; i < num_freelists; ++i) {
uint free_size = i << log2_obj_align_mod;
@@ -285,24 +294,30 @@ object_size_valid(const obj_header_t * pre, uint size, const chunk_t * cp)
#if IGC_PTR_STABILITY_CHECK
void ialloc_validate_pointer_stability(const obj_header_t * ptr_from,
const obj_header_t * ptr_to);
-static void ialloc_validate_ref(const ref *, gc_state_t *, const obj_header_t *pre_fr);
-static void ialloc_validate_ref_packed(const ref_packed *, gc_state_t *, const obj_header_t *pre_fr);
+static int ialloc_validate_ref(const ref *, gc_state_t *, const obj_header_t *pre_fr);
+static int ialloc_validate_ref_packed(const ref_packed *, gc_state_t *, const obj_header_t *pre_fr);
#else
-static void ialloc_validate_ref(const ref *, gc_state_t *);
-static void ialloc_validate_ref_packed(const ref_packed *, gc_state_t *);
+static int ialloc_validate_ref(const ref *, gc_state_t *);
+static int ialloc_validate_ref_packed(const ref_packed *, gc_state_t *);
#endif
-void
-ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
+static int
+do_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
{
+ int ret = 0;
+
if_debug_chunk('6', "[6]validating chunk", cp);
SCAN_CHUNK_OBJECTS(cp);
DO_ALL
if (pre->o_type == &st_free) {
- if (!object_size_valid(pre, size, cp))
+ if (!object_size_valid(pre, size, cp)) {
lprintf3("Bad free object 0x%lx(%lu), in chunk 0x%lx!\n",
(ulong) (pre + 1), (ulong) size, (ulong) cp);
- } else
- ialloc_validate_object(pre + 1, cp, gcst);
+ return 1;
+ }
+ } else if (do_validate_object(pre + 1, cp, gcst)) {
+ dprintf_chunk("while validating chunk", cp);
+ return 1;
+ }
if_debug3('7', " [7]validating %s(%lu) 0x%lx\n",
struct_type_name_string(pre->o_type),
(ulong) size, (ulong) pre);
@@ -312,10 +327,17 @@ ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
while ((const char *)rp < end) {
# if IGC_PTR_STABILITY_CHECK
- ialloc_validate_ref_packed(rp, gcst, pre);
+ ret = ialloc_validate_ref_packed(rp, gcst, pre);
# else
- ialloc_validate_ref_packed(rp, gcst);
+ ret = ialloc_validate_ref_packed(rp, gcst);
# endif
+ if (ret) {
+ lprintf3("while validating %s(%lu) 0x%lx\n",
+ struct_type_name_string(pre->o_type),
+ (ulong) size, (ulong) pre);
+ dprintf_chunk("in chunk", cp);
+ return ret;
+ }
rp = packed_next(rp);
}
} else {
@@ -332,24 +354,37 @@ ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
DO_NOTHING;
/* NB check other types ptr_string_type, etc. */
else if (ptype == ptr_struct_type) {
- ialloc_validate_object(eptr.ptr, NULL, gcst);
+ ret = do_validate_object(eptr.ptr, NULL, gcst);
# if IGC_PTR_STABILITY_CHECK
ialloc_validate_pointer_stability(pre,
- (const obj_header_t *)eptr.ptr - 1);
+ (const obj_header_t *)eptr.ptr - 1);
# endif
} else if (ptype == ptr_ref_type)
# if IGC_PTR_STABILITY_CHECK
- ialloc_validate_ref_packed(eptr.ptr, gcst, pre);
+ ret = ialloc_validate_ref_packed(eptr.ptr, gcst, pre);
# else
- ialloc_validate_ref_packed(eptr.ptr, gcst);
+ ret = ialloc_validate_ref_packed(eptr.ptr, gcst);
# endif
+ if (ret) {
+ dprintf_chunk("while validating chunk", cp);
+ return ret;
+ }
}
}
END_OBJECTS_SCAN
+ return ret;
}
+
+void
+ialloc_validate_chunk(const chunk_t * cp, gc_state_t * gcst)
+{
+ if (do_validate_chunk(cp, gcst))
+ gs_abort(gcst->heap);
+}
+
/* Validate a ref. */
#if IGC_PTR_STABILITY_CHECK
-static void
+static int
ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst, const obj_header_t *pre_fr)
{
const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory;
@@ -358,13 +393,13 @@ ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst, const obj_h
ref unpacked;
packed_get(cmem, rp, &unpacked);
- ialloc_validate_ref(&unpacked, gcst, pre_fr);
+ return ialloc_validate_ref(&unpacked, gcst, pre_fr);
} else {
- ialloc_validate_ref((const ref *)rp, gcst, pre_fr);
+ return ialloc_validate_ref((const ref *)rp, gcst, pre_fr);
}
}
#else
-static void
+static int
ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst)
{
const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory;
@@ -373,13 +408,13 @@ ialloc_validate_ref_packed(const ref_packed * rp, gc_state_t * gcst)
ref unpacked;
packed_get(cmem, rp, &unpacked);
- ialloc_validate_ref(&unpacked, gcst);
+ return ialloc_validate_ref(&unpacked, gcst);
} else {
- ialloc_validate_ref((const ref *)rp, gcst);
+ return ialloc_validate_ref((const ref *)rp, gcst);
}
}
#endif
-static void
+static int
ialloc_validate_ref(const ref * pref, gc_state_t * gcst
# if IGC_PTR_STABILITY_CHECK
, const obj_header_t *pre_fr
@@ -391,11 +426,12 @@ ialloc_validate_ref(const ref * pref, gc_state_t * gcst
const char *tname;
uint size;
const gs_memory_t *cmem = gcst->spaces.memories.named.system->stable_memory;
+ int ret = 0;
if (!gs_debug_c('?'))
- return; /* no check */
+ return 0; /* no check */
if (r_space(pref) == avm_foreign)
- return;
+ return 0;
switch (r_type(pref)) {
case t_file:
optr = pref->value.pfile;
@@ -408,11 +444,16 @@ ialloc_validate_ref(const ref * pref, gc_state_t * gcst
case t_astruct:
optr = pref->value.pstruct;
cks: if (optr != 0) {
- ialloc_validate_object(optr, NULL, gcst);
+ ret = do_validate_object(optr, NULL, gcst);
# if IGC_PTR_STABILITY_CHECK
ialloc_validate_pointer_stability(pre_fr,
- (const obj_header_t *)optr - 1);
+ (const obj_header_t *)optr - 1);
# endif
+ if (ret) {
+ lprintf1("while validating 0x%lx (fontID/struct/astruct)\n",
+ pref);
+ return ret;
+ }
}
break;
case t_name:
@@ -420,6 +461,7 @@ cks: if (optr != 0) {
lprintf3("At 0x%lx, bad name %u, pname = 0x%lx\n",
(ulong) pref, (uint)name_index(cmem, pref),
(ulong) pref->value.pname);
+ ret = 1;
break;
} {
ref sref;
@@ -432,14 +474,17 @@ cks: if (optr != 0) {
(ulong) pref, (uint) r_size(pref),
(ulong) pref->value.pname,
(ulong) sref.value.const_bytes);
+ ret = 1;
}
}
break;
case t_string:
- if (r_size(pref) != 0 && !gc_locate(pref->value.bytes, gcst))
+ if (r_size(pref) != 0 && !gc_locate(pref->value.bytes, gcst)) {
lprintf3("At 0x%lx, string ptr 0x%lx[%u] not in any chunk\n",
(ulong) pref, (ulong) pref->value.bytes,
(uint) r_size(pref));
+ ret = 1;
+ }
break;
case t_array:
if (r_size(pref) == 0)
@@ -450,6 +495,7 @@ cks: if (optr != 0) {
cka: if (!gc_locate(rptr, gcst)) {
lprintf3("At 0x%lx, %s 0x%lx not in any chunk\n",
(ulong) pref, tname, (ulong) rptr);
+ ret = 1;
break;
} {
uint i;
@@ -457,9 +503,11 @@ cka: if (!gc_locate(rptr, gcst)) {
for (i = 0; i < size; ++i) {
const ref *elt = rptr + i;
- if (r_is_packed(elt))
+ if (r_is_packed(elt)) {
lprintf5("At 0x%lx, %s 0x%lx[%u] element %u is not a ref\n",
(ulong) pref, tname, (ulong) rptr, size, i);
+ ret = 1;
+ }
}
}
break;
@@ -468,9 +516,11 @@ cka: if (!gc_locate(rptr, gcst)) {
if (r_size(pref) == 0)
break;
optr = pref->value.packed;
- if (!gc_locate(optr, gcst))
+ if (!gc_locate(optr, gcst)) {
lprintf2("At 0x%lx, packed array 0x%lx not in any chunk\n",
(ulong) pref, (ulong) optr);
+ ret = 1;
+ }
break;
case t_dictionary:
{
@@ -480,15 +530,18 @@ cka: if (!gc_locate(rptr, gcst)) {
!r_is_array(&pdict->keys) ||
!r_has_type(&pdict->count, t_integer) ||
!r_has_type(&pdict->maxlength, t_integer)
- )
+ ) {
lprintf2("At 0x%lx, invalid dict 0x%lx\n",
(ulong) pref, (ulong) pdict);
+ ret = 1;
+ }
rptr = (const ref *)pdict;
}
size = sizeof(dict) / sizeof(ref);
tname = "dict";
goto cka;
}
+ return ret;
}
#if IGC_PTR_STABILITY_CHECK
@@ -515,8 +568,8 @@ ialloc_validate_pointer_stability(const obj_header_t * ptr_fr,
#endif
/* Validate an object. */
-void
-ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
+static int
+do_validate_object(const obj_header_t * ptr, const chunk_t * cp,
gc_state_t * gcst)
{
const obj_header_t *pre = ptr - 1;
@@ -525,7 +578,7 @@ ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
const char *oname;
if (!gs_debug_c('?'))
- return; /* no check */
+ return 0; /* no check */
if (cp == 0 && gcst != 0) {
gc_state_t st;
@@ -533,13 +586,13 @@ ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
if (!(cp = gc_locate(pre, &st))) {
lprintf1("Object 0x%lx not in any chunk!\n",
(ulong) ptr);
- return; /*gs_abort(); */
+ return 1; /*gs_abort(); */
}
}
if (otype == &st_free) {
lprintf3("Reference to free object 0x%lx(%lu), in chunk 0x%lx!\n",
(ulong) ptr, (ulong) size, (ulong) cp);
- gs_abort(gcst->heap);
+ return 1;
}
if ((cp != 0 && !object_size_valid(pre, size, cp)) ||
otype->ssize == 0 ||
@@ -551,10 +604,18 @@ ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
(ulong) ptr, (ulong) size);
dprintf2(" ssize = %u, in chunk 0x%lx!\n",
otype->ssize, (ulong) cp);
- gs_abort(gcst->heap);
+ return 1;
}
+ return 0;
}
+void
+ialloc_validate_object(const obj_header_t * ptr, const chunk_t * cp,
+ gc_state_t * gcst)
+{
+ if (do_validate_object(ptr, cp, gcst))
+ gs_abort(gcst->heap);
+}
#else /* !DEBUG */
void
diff --git a/gs/psi/interp.c b/gs/psi/interp.c
index b3ab68f8f..e6f8f1a22 100644
--- a/gs/psi/interp.c
+++ b/gs/psi/interp.c
@@ -82,6 +82,8 @@ do_call_operator(op_proc_t op_proc, i_ctx_t *i_ctx_p)
{
int code;
code = op_proc(i_ctx_p);
+ if (gs_debug_c(gs_debug_flag_validate_chunks))
+ ivalidate_clean_spaces(i_ctx_p);
return code; /* A good place for a conditional breakpoint. */
}
static int
@@ -103,6 +105,8 @@ do_call_operator_verbose(op_proc_t op_proc, i_ctx_t *i_ctx_p)
esp-i_ctx_p->exec_stack.stack.bot,
osp-i_ctx_p->op_stack.stack.bot);
#endif
+ if (gs_debug_c(gs_debug_flag_validate_chunks))
+ ivalidate_clean_spaces(i_ctx_p);
return code; /* A good place for a conditional breakpoint. */
}
#else
diff --git a/gs/psi/zvmem.c b/gs/psi/zvmem.c
index a5c6b1255..aa477b0d3 100644
--- a/gs/psi/zvmem.c
+++ b/gs/psi/zvmem.c
@@ -46,7 +46,7 @@ gs_private_st_ptrs1(st_vm_save, vm_save_t, "savetype",
vm_save_enum_ptrs, vm_save_reloc_ptrs, gsave);
/* Clean up the stacks and validate storage. */
-static void
+void
ivalidate_clean_spaces(i_ctx_t *i_ctx_p)
{
if (gs_debug_c('?')) {