~mcf/mupdf

ref: e27ceb2b0e64b9a56ba79d844ea96553d87dc113 mupdf/platform/java/jni/context.c -rw-r--r-- 4.8 KiB
e27ceb2b — Robin Watts OSS-Fuzz 29728: Avoid buffer overflow. 1 year, 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/* Context interface */

/* Put the fz_context in thread-local storage */

#ifdef _WIN32
static CRITICAL_SECTION mutexes[FZ_LOCK_MAX];
#else
static pthread_mutex_t mutexes[FZ_LOCK_MAX];
#endif

static void lock(void *user, int lock)
{
#ifdef _WIN32
	EnterCriticalSection(&mutexes[lock]);
#else
	(void)pthread_mutex_lock(&mutexes[lock]);
#endif
}

static void unlock(void *user, int lock)
{
#ifdef _WIN32
	LeaveCriticalSection(&mutexes[lock]);
#else
	(void)pthread_mutex_unlock(&mutexes[lock]);
#endif
}


static const fz_locks_context locks =
{
	NULL, /* user */
	lock,
	unlock
};

static void fin_base_context(JNIEnv *env)
{
	int i;

	fz_drop_context(base_context);
	base_context = NULL;

	for (i = 0; i < FZ_LOCK_MAX; i++)
#ifdef _WIN32
		DeleteCriticalSection(&mutexes[i]);
#else
		(void)pthread_mutex_destroy(&mutexes[i]);
#endif
}

#ifndef _WIN32
static void drop_tls_context(void *arg)
{
	fz_context *ctx = (fz_context *)arg;

	fz_drop_context(ctx);
}
#endif

static int init_base_context(JNIEnv *env)
{
	int i;

#ifdef _WIN32
	/* No destructor on windows. We will leak contexts.
	 * There is no easy way around this, but this page:
	 * http://stackoverflow.com/questions/3241732/is-there-anyway-to-dynamically-free-thread-local-storage-in-the-win32-apis/3245082#3245082
	 * suggests a workaround that we can implement if we
	 * need to. */
	context_key = TlsAlloc();
	if (context_key == TLS_OUT_OF_INDEXES)
	{
		LOGE("cannot get thread local storage for storing base context");
		return -1;
	}
#else
	int ret = pthread_key_create(&context_key, drop_tls_context);
	if (ret < 0)
	{
		LOGE("cannot get thread local storage for storing base context");
		return -1;
	}
#endif

	for (i = 0; i < FZ_LOCK_MAX; i++)
#ifdef _WIN32
		InitializeCriticalSection(&mutexes[i]);
#else
		(void)pthread_mutex_init(&mutexes[i], NULL);
#endif

	base_context = fz_new_context(NULL, &locks, FZ_STORE_DEFAULT);
	if (!base_context)
	{
		LOGE("cannot create base context");
		fin_base_context(env);
		return -1;
	}

	fz_try(base_context)
		fz_register_document_handlers(base_context);
	fz_catch(base_context)
	{
		LOGE("cannot register document handlers (%s)", fz_caught_message(base_context));
		fin_base_context(env);
		return -1;
	}

#ifdef HAVE_ANDROID
	fz_install_load_system_font_funcs(base_context,
		load_droid_font,
		load_droid_cjk_font,
		load_droid_fallback_font);
#endif

	return 0;
}

static fz_context *get_context(JNIEnv *env)
{
	fz_context *ctx = (fz_context *)
#ifdef _WIN32
		TlsGetValue(context_key);
	if (ctx == NULL && GetLastError() != ERROR_SUCCESS) jni_throw_run(env, "cannot get context");
#else
		pthread_getspecific(context_key);
#endif

	if (ctx)
		return ctx;

	ctx = fz_clone_context(base_context);
	if (!ctx) jni_throw_oom(env, "failed to clone fz_context");

#ifdef _WIN32
	if (TlsSetValue(context_key, ctx) == 0) jni_throw_run(env, "cannot store context");
#else
	if (pthread_setspecific(context_key, ctx) != 0) jni_throw_run(env, "cannot store context");
#endif
	return ctx;
}


JNIEXPORT jint JNICALL
FUN(Context_initNative)(JNIEnv *env, jclass cls)
{
	if (!check_enums())
		return -1;

	/* Must init the context before find_finds, because the act of
	 * finding the fids can cause classes to load. This causes
	 * statics to be setup, which can in turn call JNI code, which
	 * requires the context. (For example see ColorSpace) */
	if (init_base_context(env) < 0)
		return -1;

	if (find_fids(env) < 0)
	{
		fin_base_context(env);
		return -1;
	}

	return 0;
}

JNIEXPORT void JNICALL
FUN(Context_emptyStore)(JNIEnv *env, jclass cls)
{
	fz_context *ctx = get_context(env);
	if (!ctx) return;

	fz_empty_store(ctx);
}

JNIEXPORT void JNICALL
FUN(Context_enableICC)(JNIEnv *env, jclass cls)
{
	fz_context *ctx = get_context(env);
	if (!ctx) return;

	fz_enable_icc(ctx);
}

JNIEXPORT void JNICALL
FUN(Context_disableICC)(JNIEnv *env, jclass cls)
{
	fz_context *ctx = get_context(env);
	if (!ctx) return;

	fz_disable_icc(ctx);
}

JNIEXPORT void JNICALL
FUN(Context_setAntiAliasLevel)(JNIEnv *env, jclass cls, jint level)
{
	fz_context *ctx = get_context(env);
	if (!ctx) return;

	fz_set_aa_level(ctx, level);
}

JNIEXPORT jobject JNICALL
FUN(Context_getVersion)(JNIEnv *env, jclass cls)
{
	fz_context *ctx = get_context(env);
	jobject jversion = NULL;
	jobject jvs = NULL;

	if (!ctx) return NULL;

	jvs = (*env)->NewStringUTF(env, FZ_VERSION);
	if (!jvs || (*env)->ExceptionCheck(env))
		return NULL;

	jversion = (*env)->NewObject(env, cls_Context_Version, mid_Context_Version_init);
	if (!jversion || (*env)->ExceptionCheck(env))
		return NULL;

	(*env)->SetIntField(env, jversion, fid_Context_Version_major, FZ_VERSION_MAJOR);
	(*env)->SetIntField(env, jversion, fid_Context_Version_minor, FZ_VERSION_MINOR);
	(*env)->SetIntField(env, jversion, fid_Context_Version_patch, FZ_VERSION_PATCH);
	(*env)->SetObjectField(env, jversion, fid_Context_Version_version, jvs);

	return jversion;
}