JNI crashes in FontManager code
Martin Buchholz
martinrb at google.com
Thu Oct 16 17:23:03 PDT 2008
Hi font maintainers,
This is a bug report, with fix,
provided by Hiroshi Yamauchi.
This is a crash detected by a google test
(which is unfortunately impractical to share)
which makes this at least a P2 bug.
Description:
Fixing the bad JNI code in the font manager code. Two issues:
o The JNIEnv is unique to the thread. It cannot be saved by one thread and
reused by another. Use GetEnv instead.
o The 'font2D' jobject needs to be converted into a global reference because
its lifetime exceeds the lifetime of a native method call.
Evaluation:
Appropriately register/free everything with the garbage collector.
Fix:
# HG changeset patch
# User martin
# Date 1224202830 25200
# Node ID 3c9d6001d8a90698a3540a2a483717f26a98db78
# Parent 68730f05449cd4f39ce1cb82adc6c4e57f87554f
Crash in freetypeScaler.c due to insufficient GC protection
Summary: NewGlobalRef/DeleteGlobalRef as needed.
Reviewed-by:
Contributed-by: yamauchi at google.com
diff --git a/make/sun/font/mapfile-vers.openjdk
b/make/sun/font/mapfile-vers.openjdk
--- a/make/sun/font/mapfile-vers.openjdk
+++ b/make/sun/font/mapfile-vers.openjdk
@@ -29,6 +29,7 @@
SUNWprivate_1.1 {
global:
+ JNI_OnLoad;
getSunFontIDs;
newLayoutTableCache;
freeLayoutTableCache;
diff --git a/src/share/native/sun/font/freetypeScaler.c
b/src/share/native/sun/font/freetypeScaler.c
--- a/src/share/native/sun/font/freetypeScaler.c
+++ b/src/share/native/sun/font/freetypeScaler.c
@@ -48,16 +48,6 @@
#define ROUND(x) ((int) (x+0.5))
typedef struct {
- /* Important note:
- JNI forbids sharing same env between different threads.
- We are safe, because pointer is overwritten every time we get into
- JNI call (see setupFTContext).
-
- Pointer is used by font data reading callbacks
- such as ReadTTFontFileFunc.
-
- NB: We may consider switching to JNI_GetEnv. */
- JNIEnv* env;
FT_Library library;
FT_Face face;
jobject font2D;
@@ -90,6 +80,13 @@
void z_error(char *s) {}
#endif
+static JavaVM* jvm = NULL;
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
+ jvm = vm;
+ return JNI_VERSION_1_2;
+}
+
/**************** Error handling utilities *****************/
static jmethodID invalidateScalerMID;
@@ -107,6 +104,10 @@
FT_Done_Face(scalerInfo->face);
FT_Done_FreeType(scalerInfo->library);
+
+ if (scalerInfo->font2D != NULL) {
+ (*env)->DeleteGlobalRef(env, scalerInfo->font2D);
+ }
if (scalerInfo->directBuffer != NULL) {
(*env)->DeleteGlobalRef(env, scalerInfo->directBuffer);
@@ -131,10 +132,9 @@
#define FILEDATACACHESIZE 1024
-/* NB: is it ever called? */
static void CloseTTFontFileFunc(FT_Stream stream) {
+ JNIEnv* env = (JNIEnv*) JNU_GetEnv(jvm, JNI_VERSION_1_2);
FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
- JNIEnv* env = scalerInfo->env;
jclass tmpClass = (*env)->FindClass(env, "sun/font/TrueTypeFont");
jfieldID platNameField =
(*env)->GetFieldID(env, tmpClass, "platName", "Ljava/lang/String;");
@@ -150,8 +150,8 @@
unsigned char* destBuffer,
unsigned long numBytes)
{
+ JNIEnv* env = (JNIEnv*) JNU_GetEnv(jvm, JNI_VERSION_1_2);
FTScalerInfo *scalerInfo = (FTScalerInfo *) stream->pathname.pointer;
- JNIEnv* env = scalerInfo->env;
jobject bBuffer;
int bread = 0;
@@ -245,8 +245,7 @@
if (scalerInfo == NULL)
return 0;
- scalerInfo->env = env;
- scalerInfo->font2D = font2D;
+ scalerInfo->font2D = (*env)->NewGlobalRef(env, font2D);
scalerInfo->fontDataOffset = 0;
scalerInfo->fontDataLength = 0;
scalerInfo->fileSize = filesize;
@@ -263,6 +262,7 @@
*/
error = FT_Init_FreeType(&scalerInfo->library);
if (error) {
+ (*env)->DeleteGlobalRef(env, scalerInfo->font2D);
free(scalerInfo);
return 0;
}
@@ -331,6 +331,7 @@
}
if (scalerInfo->fontData != NULL)
free(scalerInfo->fontData);
+ (*env)->DeleteGlobalRef(env, scalerInfo->font2D);
free(scalerInfo);
return 0;
}
@@ -391,8 +392,10 @@
FTScalerContext *context) {
int errCode = 0;
- scalerInfo->env = env;
- scalerInfo->font2D = font2D;
+ if (scalerInfo->font2D != NULL) {
+ (*env)->DeleteGlobalRef(env, scalerInfo->font2D);
+ }
+ scalerInfo->font2D = (*env)->NewGlobalRef(env, font2D);
FT_Set_Transform(scalerInfo->face, &context->transform, NULL);
More information about the jdk6-dev
mailing list