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?