commit - 8993cef512f4545c0e407a733bae4fa4225f3989
commit + b5568c0ce46c37f080fe97f45bfb67e9744e8fde
blob - 4c8803047ec8b12e70a961b92abc801055c852e8
blob + b8bbb7e80784e56ddb6d2899270662ef980b569a
--- pdf.c
+++ pdf.c
const HParsedToken *
resolve(struct Env *aux, const HParsedToken *v)
{
+ static void *INVALID = &INVALID; /* a reserved dummy pointer */
XREntry *ent = NULL;
Ref *r;
* The null object maps to NULL. This makes it equivalent to a
* nonexistent object and covers the handling of (indirect) null values
* in dictionaries (treating them as if the entry did not exist).
+ *
+ * Likewise, we map invalid (e.g. circular) references to NULL.
*/
- if (v == NULL || v->token_type == TT_Null)
+ if (v == NULL || v == INVALID || v->token_type == TT_Null)
return NULL;
/* other direct objects pass through */
if (ent->obj != NULL)
return resolve(aux, ent->obj);
- /* parse the object and memoize */
- ent->obj = v; /* break loops */
+ /* parse the object */
switch (ent->type)
{
case XR_FREE:
case XR_INUSE:
if (ent->n.gen != r->gen)
return NULL; /* obj nr reused */
- ent->obj = parse_obj(aux, r->nr, r->gen, ent->n.offs);
+ v = parse_obj(aux, r->nr, r->gen, ent->n.offs);
break;
case XR_OBJSTM:
if (r->gen != 0)
return NULL; /* invalid entry! */
- ent->obj = parse_objstm_obj(aux, r->nr, ent->o.stm, ent->o.idx);
+ v = parse_objstm_obj(aux, r->nr, ent->o.stm, ent->o.idx);
break;
default:
/*
return NULL;
}
- return resolve(aux, ent->obj);
+ /* resolve recursively and memoize */
+ ent->obj = INVALID; /* break loops */
+ if ((v = resolve(aux, v)) != NULL)
+ ent->obj = v;
+
+ assert(v != INVALID); /* our dummy does not escape */
+ return v;
}