Changing resource pack that overrides a font crashes JVM. Not Minecraft crash.
I'm making a font resource pack for upcoming 1.20 version, so I tried to reload it to apply changes. And then BOOM! The JVM has crashed.
This occurs when triggering some event for a resource pack, such as changing the order, disabling, pressing F3+T to reload, ᅟor quitting Minecraft.
The font resource pack overrides 'default' font using a truetype font (.ttf) file.
Attachments
Comments 3
Code analysis (23w18a)
Yarn names are used here: 23w18+build.1
for 23w18a. The decompiled code shown below has been generated using Fabric’s fork of CFR.
FontManager#reload
has this chunk of code, closing each loaded font storage, then closing each font:
this.fontStorages.values().forEach(FontStorage::close);
this.fontStorages.clear();
this.fonts.forEach(Font::close);
this.fonts.clear();
Looking at {{FontStorage}}’s code, we find the following:
@Override
public void close() {
this.closeFonts();
this.closeGlyphAtlases();
}
private void closeFonts() {
for (Font font : this.fonts) {
font.close();
}
this.fonts.clear();
}
private void closeGlyphAtlases() {
for (GlyphAtlasTexture glyphAtlasTexture : this.glyphAtlases) {
glyphAtlasTexture.close();
}
this.glyphAtlases.clear();
}
The problem is that the font storage objects in FontManager#fontStorages
refer to the same fonts as the ones in FontManager#fonts
. This causes some fonts to be closed more than once. BitmapFont}}’s implementation of {{Font#close
protects against multiple calls, but TrueTypeFont}}’s implementation does not – calling {{close
more than once on a TrueTypeFont
causes a double free, resulting in a JVM crash.
Likewise, FontManager#close
also causes the same type of double free.
A possible solution would be to have FontStorage
not be responsible for closing its fonts. Alternatively, each subclass of Font
could protect against multiple closes, but this is a hacky solution in my opinion.
Could you please attach a sample resource pack to this issue?