commit da562f47c891cc2678b984fafdc886764783bf4b from: Sven M. Hallberg date: Tue Aug 09 19:27:42 2022 UTC support cyclic references in resolve_item() Duplicates the previous commit. Note that we must pull the INVALID pointer out of resolve() so that resolve_item() can use the same one. Otherwise, the two function could confuse each others' INVALID pointers for valid objects. commit - b5568c0ce46c37f080fe97f45bfb67e9744e8fde commit + da562f47c891cc2678b984fafdc886764783bf4b blob - b8bbb7e80784e56ddb6d2899270662ef980b569a blob + 8cc9cd17b99a35b19a32ef4eb9f1e5f3676ee54c --- pdf.c +++ pdf.c @@ -2826,10 +2826,11 @@ parse_objstm_obj(struct Env *aux, size_t nr, size_t st } /* resolve a parsed object to its final semantic value */ + static void *INVALID = &INVALID; /* a reserved dummy pointer */ + // XXX move this back into the function const HParsedToken * resolve(struct Env *aux, const HParsedToken *v) { - static void *INVALID = &INVALID; /* a reserved dummy pointer */ XREntry *ent = NULL; Ref *r; @@ -3642,9 +3643,8 @@ resolve_item(struct Env *aux, const HParsedToken *v, s XREntry *ent = NULL; Ref *r; - /* the null object maps 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 */ @@ -3662,8 +3662,7 @@ resolve_item(struct Env *aux, const HParsedToken *v, s if (ent->obj != NULL) return resolve_item(aux, ent->obj, offset, p); - /* parse the object and memoize */ - ent->obj = v; /* break loops */ + /* parse the object */ switch (ent->type) { case XR_FREE: @@ -3671,13 +3670,13 @@ resolve_item(struct Env *aux, const HParsedToken *v, s case XR_INUSE: if (ent->n.gen != r->gen) return NULL; /* obj nr reused */ - ent->obj = parse_item(aux, r->nr, r->gen, ent->n.offs, p); + v = parse_item(aux, r->nr, r->gen, ent->n.offs, p); *offset = ent->n.offs; break; case XR_OBJSTM: if (r->gen != 0) return NULL; /* invalid entry! */ - ent->obj = parse_objstm_item(aux, r->nr, ent->o.stm, ent->o.idx, offset, p); + v = parse_objstm_item(aux, r->nr, ent->o.stm, ent->o.idx, offset, p); break; default: /* @@ -3687,7 +3686,13 @@ resolve_item(struct Env *aux, const HParsedToken *v, s return NULL; } - return resolve_item(aux, ent->obj, offset, p); + /* resolve recursively and memoize */ + ent->obj = INVALID; /* break loops */ + if ((v = resolve_item(aux, v, offset, p)) != NULL) + ent->obj = v; + + assert(v != INVALID); /* our dummy does not escape */ + return v; }