-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
P4
-
Affects Version/s: 25
-
Component/s: client-libs
-
linux
ADDITIONAL SYSTEM INFORMATION :
Property settings:
file.encoding = UTF-8
file.separator = /
java.class.path =
java.class.version = 69.0
java.home = /usr/lib/jvm/java-25-amazon-corretto.aarch64
java.io.tmpdir = /tmp
java.library.path = /usr/java/packages/lib
/usr/lib64
/lib64
/lib
/usr/lib
java.runtime.name = OpenJDK Runtime Environment
java.runtime.version = 25.0.2+10-LTS
java.specification.name = Java Platform API Specification
java.specification.vendor = Oracle Corporation
java.specification.version = 25
java.vendor = Amazon.com Inc.
java.vendor.url = https://aws.amazon.com/corretto/
java.vendor.url.bug = https://github.com/corretto/corretto-25/issues/
java.vendor.version = Corretto-25.0.2.10.1
java.version = 25.0.2
java.version.date = 2026-01-20
java.vm.compressedOopsMode = Zero based
java.vm.info = mixed mode, sharing
java.vm.name = OpenJDK 64-Bit Server VM
java.vm.specification.name = Java Virtual Machine Specification
java.vm.specification.vendor = Oracle Corporation
java.vm.specification.version = 25
java.vm.vendor = Amazon.com Inc.
java.vm.version = 25.0.2+10-LTS
jdk.debug = release
line.separator = \n
native.encoding = UTF-8
os.arch = aarch64
os.name = Linux
os.version = 6.17.8-orbstack-00308-g8f9c941121b1
path.separator = :
stderr.encoding = UTF-8
stdin.encoding = UTF-8
stdout.encoding = UTF-8
sun.arch.data.model = 64
sun.boot.library.path = /usr/lib/jvm/java-25-amazon-corretto.aarch64/lib
sun.cpu.endian = little
sun.io.unicode.encoding = UnicodeLittle
sun.java.launcher = SUN_STANDARD
sun.jnu.encoding = UTF-8
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
user.dir = /
user.home = /root
user.language = en
user.name = root
openjdk version "25.0.2" 2026-01-20 LTS
OpenJDK Runtime Environment Corretto-25.0.2.10.1 (build 25.0.2+10-LTS)
OpenJDK 64-Bit Server VM Corretto-25.0.2.10.1 (build 25.0.2+10-LTS, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
If multiple threads are simultaneously using Font objects with FontAttributes set to calculate stringWidth, libfontmanager.so will try to free an address has not been allocated, causing a SIGABRT to crash the JVM. (If using something like tcmalloc or jemalloc which are stricter about memory violations like this one)
Also, the JVM does not catch the SIGABRT to create the hs_err.log, so I had to write a C wrapper library to catch it and raise SIGSEGV instead, which is why you see some extra C frames in the hs_err_log after the crash.
REGRESSION : Last worked in version 21
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Launch 2 virtual threads, both of which create a Font object, enable kerning, and try to use it to calculate the width of a string. It doesn't matter if the Font object is in a shared static field or if they create their own instance.
The timing doesn't always work with only 2 threads, so if you can't reproduce it, try launching more threads.
---------- BEGIN SOURCE ----------
Java:
public class FontCrashReproducer {
public static void main(String[] args) throws InterruptedException {
var t1 = Thread.ofVirtual().start(() -> handle("oh"));
var t2 = Thread.ofVirtual().start(() -> handle("no"));
t1.join();
t2.join();
System.out.println("Failed to crash as expected");
}
public static Font createFont() {
try {
// Loading a random font which happens to be available in the Docker image to simplify reproducer
var font = Font.createFont(Font.TRUETYPE_FONT, Paths.get("/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf").toFile());
var map = new HashMap<TextAttribute, Object>();
map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); // Disabling Kerning avoids the bug
return font.deriveFont(map);
} catch (FontFormatException | IOException e) {
throw new RuntimeException(e);
}
}
public static void handle(String text) {
var img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
var canvas = img.createGraphics();
canvas.setFont(createFont());
var fontMetrics = canvas.getFontMetrics();
fontMetrics.stringWidth(text);
}
}
Dockerfile:
FROM amazoncorretto:25-al2023
RUN dnf install gperftools-libs -y
COPY ./build/libs/app.jar /app.jar
ENV LD_PRELOAD="/usr/lib64/libtcmalloc.so.4"
ENTRYPOINT ["java", "-jar", "app.jar"]
I use amazoncorretto here in my example, but I've also tested with Fedora and OpenJDK 25
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Passing an empty Map to derive font instead of setting any FontAttributes also avoids the crash.
FREQUENCY :
ALWAYS
Property settings:
file.encoding = UTF-8
file.separator = /
java.class.path =
java.class.version = 69.0
java.home = /usr/lib/jvm/java-25-amazon-corretto.aarch64
java.io.tmpdir = /tmp
java.library.path = /usr/java/packages/lib
/usr/lib64
/lib64
/lib
/usr/lib
java.runtime.name = OpenJDK Runtime Environment
java.runtime.version = 25.0.2+10-LTS
java.specification.name = Java Platform API Specification
java.specification.vendor = Oracle Corporation
java.specification.version = 25
java.vendor = Amazon.com Inc.
java.vendor.url = https://aws.amazon.com/corretto/
java.vendor.url.bug = https://github.com/corretto/corretto-25/issues/
java.vendor.version = Corretto-25.0.2.10.1
java.version = 25.0.2
java.version.date = 2026-01-20
java.vm.compressedOopsMode = Zero based
java.vm.info = mixed mode, sharing
java.vm.name = OpenJDK 64-Bit Server VM
java.vm.specification.name = Java Virtual Machine Specification
java.vm.specification.vendor = Oracle Corporation
java.vm.specification.version = 25
java.vm.vendor = Amazon.com Inc.
java.vm.version = 25.0.2+10-LTS
jdk.debug = release
line.separator = \n
native.encoding = UTF-8
os.arch = aarch64
os.name = Linux
os.version = 6.17.8-orbstack-00308-g8f9c941121b1
path.separator = :
stderr.encoding = UTF-8
stdin.encoding = UTF-8
stdout.encoding = UTF-8
sun.arch.data.model = 64
sun.boot.library.path = /usr/lib/jvm/java-25-amazon-corretto.aarch64/lib
sun.cpu.endian = little
sun.io.unicode.encoding = UnicodeLittle
sun.java.launcher = SUN_STANDARD
sun.jnu.encoding = UTF-8
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
user.dir = /
user.home = /root
user.language = en
user.name = root
openjdk version "25.0.2" 2026-01-20 LTS
OpenJDK Runtime Environment Corretto-25.0.2.10.1 (build 25.0.2+10-LTS)
OpenJDK 64-Bit Server VM Corretto-25.0.2.10.1 (build 25.0.2+10-LTS, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
If multiple threads are simultaneously using Font objects with FontAttributes set to calculate stringWidth, libfontmanager.so will try to free an address has not been allocated, causing a SIGABRT to crash the JVM. (If using something like tcmalloc or jemalloc which are stricter about memory violations like this one)
Also, the JVM does not catch the SIGABRT to create the hs_err.log, so I had to write a C wrapper library to catch it and raise SIGSEGV instead, which is why you see some extra C frames in the hs_err_log after the crash.
REGRESSION : Last worked in version 21
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Launch 2 virtual threads, both of which create a Font object, enable kerning, and try to use it to calculate the width of a string. It doesn't matter if the Font object is in a shared static field or if they create their own instance.
The timing doesn't always work with only 2 threads, so if you can't reproduce it, try launching more threads.
---------- BEGIN SOURCE ----------
Java:
public class FontCrashReproducer {
public static void main(String[] args) throws InterruptedException {
var t1 = Thread.ofVirtual().start(() -> handle("oh"));
var t2 = Thread.ofVirtual().start(() -> handle("no"));
t1.join();
t2.join();
System.out.println("Failed to crash as expected");
}
public static Font createFont() {
try {
// Loading a random font which happens to be available in the Docker image to simplify reproducer
var font = Font.createFont(Font.TRUETYPE_FONT, Paths.get("/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf").toFile());
var map = new HashMap<TextAttribute, Object>();
map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON); // Disabling Kerning avoids the bug
return font.deriveFont(map);
} catch (FontFormatException | IOException e) {
throw new RuntimeException(e);
}
}
public static void handle(String text) {
var img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
var canvas = img.createGraphics();
canvas.setFont(createFont());
var fontMetrics = canvas.getFontMetrics();
fontMetrics.stringWidth(text);
}
}
Dockerfile:
FROM amazoncorretto:25-al2023
RUN dnf install gperftools-libs -y
COPY ./build/libs/app.jar /app.jar
ENV LD_PRELOAD="/usr/lib64/libtcmalloc.so.4"
ENTRYPOINT ["java", "-jar", "app.jar"]
I use amazoncorretto here in my example, but I've also tested with Fedora and OpenJDK 25
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Passing an empty Map to derive font instead of setting any FontAttributes also avoids the crash.
FREQUENCY :
ALWAYS