MuPDFCore icon indicating copy to clipboard operation
MuPDFCore copied to clipboard

Not calling ClearCache in finalizer causes unity to crash

Open fredlllll opened this issue 5 months ago • 2 comments

ok this is a very specific one as it only happens in unity. i naively added mupdf to my unity project to display pdfs. i then encountered crashes after exiting play mode, even though i called dispose on the context and the document. in the crash dump i found this

  ERROR: SymGetSymFromAddr64, GetLastError: 'Es wurde versucht, auf eine unzulässige Adresse zuzugreifen.' (Address: 00007FFC70D4078F)
0x00007FFC70D4078F (MuPDFWrapper) (function-name not available)
  ERROR: SymGetSymFromAddr64, GetLastError: 'Es wurde versucht, auf eine unzulässige Adresse zuzugreifen.' (Address: 00007FFC70D6E9C1)
0x00007FFC70D6E9C1 (MuPDFWrapper) (function-name not available)
0x00007FFC71218B69 (MuPDFWrapper) DisposeDisplayList
0x0000020258957F4E (Mono JIT Code) (wrapper managed-to-native) MuPDFCore.NativeMethods:DisposeDisplayList (intptr,intptr)
0x0000020258957DBB (Mono JIT Code) MuPDFCore.MuPDFDisplayList:Dispose (bool)
0x0000020258957BFC (Mono JIT Code) MuPDFCore.MuPDFDisplayList:Finalize ()
0x000002034AD01CDC (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_virtual_void__this__ (object,intptr,intptr,intptr)
0x00007FFC7F06C527 (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\mono\metadata\gc.c:383] mono_gc_run_finalize 
0x00007FFC7F2EE238 (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\external\bdwgc\finalize.c:1318] GC_invoke_finalizers 
0x00007FFC7F06DC98 (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\mono\metadata\gc.c:1035] finalizer_thread 
0x00007FFC7F00804B (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\mono\metadata\threads.c:1272] start_wrapper_internal 
0x00007FFC7F00825E (mono-2.0-bdwgc) [C:\build\output\Unity-Technologies\mono\mono\metadata\threads.c:1348] start_wrapper 
0x00007FFD1E5DE8D7 (KERNEL32) BaseThreadInitThunk
0x00007FFD1FC3C5DC (ntdll) RtlUserThreadStart

this told me that the crash was happening inside the finalizer of the display list. so i looked inside the documents dispose to see why the display lists werent disposed. but they should be, as i call dispose directly. so out of curiosity i called ClearCache on the document before disposing, and the crashes stopped. though the only thing ClearCache does different is set the entrys to null after disposing them. perhaps that is the problem?

here are the two relevant code files from the unity project, just comment out the line in PdfBook and it will crash once you leave play mode

using System;
using UnityEngine;
using UnityEngine.UI;

internal class BookView : MonoBehaviour
{
    public RawImage leftPage, rightPage;

    public Button leftButton, rightButton;

    public TextAsset bookAsset;

    PdfBook book;

    int currentLeftPage = 0;

    private void Start()
    {
        book = new PdfBook(bookAsset);
        SetCurrentLeftPage(currentLeftPage);

        rightButton.onClick.AddListener(() => { SetCurrentLeftPage(currentLeftPage + 2); });
        leftButton.onClick.AddListener(() => { SetCurrentLeftPage(currentLeftPage - 2); });
    }

    private void SetCurrentLeftPage(int page)
    {
        if (page % 2 != 0)
        {
            page--;
        }
        page = Math.Clamp(page, 0, book.MaxPageIndex);
        currentLeftPage = page;

        leftPage.texture = book.GetPage(currentLeftPage);
        if (currentLeftPage + 1 <= book.MaxPageIndex)
        {
            rightPage.texture = book.GetPage(currentLeftPage + 1);
        }
        else
        {
            rightPage.texture = null;
        }
    }
}
using MuPDFCore;
using System.Collections.Generic;
using UnityEngine;

public class PdfBook
{
    MuPDFContext context;
    MuPDFDocument document;
    Dictionary<int, Texture2D> cache = new Dictionary<int, Texture2D>();

    public float Zoom { get; set; } = 2;

    public int MaxPageIndex
    {
        get { return document.Pages.Length - 1; }
    }

    public PdfBook(TextAsset asset)
    {
        context = new MuPDFContext();
        document = new MuPDFDocument(context, asset.bytes, InputFileTypes.PDF);
    }

    ~PdfBook()
    {
        //commenting out ClearCache here will crash unity when exiting play mode
        document.ClearCache();
        document.Dispose();
        context.Dispose();
    }

    private (int, int, byte[]) GetPageData(int index)
    {
        using var page = document.Pages[index];
        var bounds = page.Bounds;
        int pixelsWidth = (int)(bounds.Width * Zoom);
        int pixelsHeight = (int)(bounds.Height * Zoom);
        return (pixelsWidth, pixelsHeight, document.Render(index, Zoom, PixelFormats.RGBA));
    }

    private Texture2D LoadPage(int index)
    {
        (int pixelsWidth, int pixelsHeight, byte[] data) = GetPageData(index);
        var texture = new Texture2D(pixelsWidth, pixelsHeight, TextureFormat.RGBA32, false);
        texture.SetPixelData(data, 0);
        texture.Apply();
        cache[index] = texture;
        return texture;
    }

    public Texture2D GetPage(int index)
    {
        if (!cache.TryGetValue(index, out var texture))
        {
            return LoadPage(index);
        }
        return texture;
    }
}

i have also uploaded a zip of the project here https://mega.nz/file/IsFCkIwC#4AAHP8G2bUCTdtHryNE2_oqel3UsJgZVmWe6v6vaJXo ~390MB

fredlllll avatar Aug 26 '25 16:08 fredlllll