summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <Robin.Watts@artifex.com>2024-01-12 17:10:06 +0000
committerRobin Watts <Robin.Watts@artifex.com>2024-01-15 12:07:47 +0000
commitb372395f690ead66d813de28bf199c5d1e60110d (patch)
treeb1c8a6b998812ca1dbcc278ba3c4d75e440ea985
parentec9420ff7c341eda5bf5480be11a75542a72ad34 (diff)
CFB handling: Improve handling of unbalanced trees.
If trees aren't balanced, we can end up exceeding our arbitrarily imposed maximum depth (seen with sample.msg). Fix that here by avoiding recursion where possible.
-rw-r--r--source/fitz/uncfb.c68
1 files changed, 45 insertions, 23 deletions
diff --git a/source/fitz/uncfb.c b/source/fitz/uncfb.c
index bfa680269..3f95aa5d8 100644
--- a/source/fitz/uncfb.c
+++ b/source/fitz/uncfb.c
@@ -585,35 +585,57 @@ make_absolute(fz_context *ctx, fz_cfb_archive *cfb, char *prefix, int node, int
{
uint32_t type;
- if (node == (int)NOSTREAM)
- return;
+ /* To avoid recursion where possible. */
+ while (1)
+ {
+ if (node == (int)NOSTREAM)
+ return;
- if (node < 0 || node >= cfb->count)
- fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid tree");
+ if (node < 0 || node >= cfb->count)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "Invalid tree");
- if (depth >= 32)
- fz_throw(ctx, FZ_ERROR_GENERIC, "CBF Tree too deep");
+ if (depth >= 32)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "CBF Tree too deep");
- type = cfb->entries[node].t;
- if (type == REACHED || type == REACHED_KEEP)
- fz_throw(ctx, FZ_ERROR_GENERIC, "CBF Tree has cycles");
- cfb->entries[node].t = (type == 2) ? REACHED_KEEP : REACHED;
+ type = cfb->entries[node].t;
+ if (type == REACHED || type == REACHED_KEEP)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "CBF Tree has cycles");
+ cfb->entries[node].t = (type == 2) ? REACHED_KEEP : REACHED;
- make_absolute(ctx, cfb, prefix, cfb->entries[node].l, depth+1);
- make_absolute(ctx, cfb, prefix, cfb->entries[node].r, depth+1);
+ if (prefix)
+ {
+ size_t z0 = strlen(prefix);
+ size_t z1 = strlen(cfb->entries[node].name);
+ char *newname = fz_malloc(ctx, z0+z1+2);
+ memcpy(newname, prefix, z0);
+ newname[z0] = '/';
+ memcpy(newname+z0+1, cfb->entries[node].name, z1+1);
+ fz_free(ctx, cfb->entries[node].name);
+ cfb->entries[node].name = newname;
+ }
- if (prefix)
- {
- size_t z0 = strlen(prefix);
- size_t z1 = strlen(cfb->entries[node].name);
- char *newname = fz_malloc(ctx, z0+z1+2);
- memcpy(newname, prefix, z0);
- newname[z0] = '/';
- memcpy(newname+z0+1, cfb->entries[node].name, z1+1);
- fz_free(ctx, cfb->entries[node].name);
- cfb->entries[node].name = newname;
+ if (cfb->entries[node].d == NOSTREAM && cfb->entries[node].r == NOSTREAM)
+ {
+ /* Handle 'l' without recursion, because there is no 'r' or 'd'. */
+ node = cfb->entries[node].l;
+ continue;
+ }
+ make_absolute(ctx, cfb, prefix, cfb->entries[node].l, depth+1);
+ if (cfb->entries[node].d == NOSTREAM)
+ {
+ /* Handle 'r' without recursion, because there is no 'd'. */
+ node = cfb->entries[node].r;
+ continue;
+ }
+ make_absolute(ctx, cfb, prefix, cfb->entries[node].r, depth+1);
+
+ /* Rather than recursing:
+ * make_absolute(ctx, cfb, node == 0 ? NULL : cfb->entries[node].name, cfb->entries[node].d, depth+1);
+ * instead just loop. */
+ prefix = node == 0 ? NULL : cfb->entries[node].name;
+ node = cfb->entries[node].d;
}
- make_absolute(ctx, cfb, node == 0 ? NULL : cfb->entries[node].name, cfb->entries[node].d, depth+1);
+
}
static void