summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-04-30 13:16:42 +0100
committerRobin Watts <robin.watts@artifex.com>2012-04-30 13:54:03 +0100
commita6d09ae879cca757a397a93bbd684b51a023637c (patch)
tree5d391d43af971ac2f5be25887e05a4dcb2f9a55d
parent2791ae43f075768c65deb9b5c6a37abfebf86d16 (diff)
downloadmupdf-a6d09ae879cca757a397a93bbd684b51a023637c.tar.xz
Fix locking issues discovered by Sebras.
When reading the xref, if certain objects are indirect references (Size, Prev, XrefStm) we can 'relock' a lock we already hold. Work around that here.
-rw-r--r--pdf/pdf_xref.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/pdf/pdf_xref.c b/pdf/pdf_xref.c
index 89333107..26d07806 100644
--- a/pdf/pdf_xref.c
+++ b/pdf/pdf_xref.c
@@ -424,9 +424,23 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf)
{
trailer = pdf_read_xref(xref, ofs, buf);
- /* FIXME: do we overwrite free entries properly? */
- xrefstm = pdf_dict_gets(trailer, "XRefStm");
- prev = pdf_dict_gets(trailer, "Prev");
+ /* Unlock file in case XRefStm or Prev are indirect. */
+ fz_unlock(ctx, FZ_LOCK_FILE);
+ fz_try(ctx)
+ {
+ /* FIXME: do we overwrite free entries properly? */
+ xrefstm = pdf_dict_gets(trailer, "XRefStm");
+ prev = pdf_dict_gets(trailer, "Prev");
+ }
+ fz_always(ctx)
+ {
+ fz_lock(ctx, FZ_LOCK_FILE);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
+
/* We only recurse if we have both xrefstm and prev.
* Hopefully this happens infrequently. */
if (xrefstm && prev)
@@ -449,6 +463,8 @@ pdf_read_xref_sections(pdf_document *xref, int ofs, pdf_lexbuf *buf)
/*
* load xref tables from pdf
+ *
+ * File locked on entry and exit; lock may be dropped in the middle.
*/
static void
@@ -464,9 +480,22 @@ pdf_load_xref(pdf_document *xref, pdf_lexbuf *buf)
pdf_read_trailer(xref, buf);
- size = pdf_dict_gets(xref->trailer, "Size");
- if (!size)
- fz_throw(ctx, "trailer missing Size entry");
+ /* Unlock (and relock) in case Size is indirect. */
+ fz_unlock(ctx, FZ_LOCK_FILE);
+ fz_try(ctx)
+ {
+ size = pdf_dict_gets(xref->trailer, "Size");
+ if (!size)
+ fz_throw(ctx, "trailer missing Size entry");
+ }
+ fz_always(ctx)
+ {
+ fz_lock(ctx, FZ_LOCK_FILE);
+ }
+ fz_catch(ctx)
+ {
+ fz_rethrow(ctx);
+ }
pdf_resize_xref(xref, pdf_to_int(size));