koreader/koreader-base

Use after free w/ PicDocument image decoding or rendering & MuPDF scaling

NiLuJe opened this issue · 5 comments

c.f. #816 for the original crash report.

The quickest repro I could get is simply to alternate between opening a PNG and viewing its cover (possibly throwing an unscale/rescale pass in the process).

i.e.,

  1. Long-press on image > "View full size cover"
  2. Original size
  3. Scale
  4. Back to FM
  5. Tap on image to "open" it
  6. Back to FM
  7. Long-press on image > "View full size cover"
  8. KABLOOEY

Tracked down to ffi/pic.lua's doc.image_bb:setAllocated(1) in openPNGDocument.
I don't know when exactly it gets free'd, but stuff blows up in ffi/mupdf.lua's fz_scale_pixmap in scaleBlitBuffer.

I'm not familiar with the BB intricacies as far as the allocated flag is concerned, and the FFI + GC interactions make my brain hurt. (Plus, LodePNG's use of a double pointer for the output buffer doesn't help).

On a hunch, I tried with a JPG: same issue ;).

(In this case, memory is allocated by BB:new, which automatically sets the allocated flag, though).

Okay, further narrowed it down to PicDocument.

If I associate an image w/ MuPDF, I can do the toggle dance all day long without a crash.
If it gets open'ed by PicDocument, the next show cover will crash.

Which neatly explains why this hadn't been caught before, I don't imagine a lot of people are actually actively using PicDocument & Show Cover in succession ;).

I remember I added PicDocument:getCoverPageImage() very quickly, without thinking much.
It may be all other xxxdocument:getCoverPageImage() returns a copy/own image object, so the code can free it with done - unlike this PicDocument:getCoverPageImage() which seem to return the object. It should just return a copy I guess.
(^ Quickly jotted down, I haven't checked much)

That appears to have hit the nail on the head, thanks @poire-z ;).