diff options
author | Robin Watts <robin.watts@artifex.com> | 2016-09-27 14:40:25 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2016-09-27 16:50:34 +0100 |
commit | 85b05e85f9952036abb61d7c99b9bb724bb22563 (patch) | |
tree | d1350b9c7a02da811ec438eae175ca9689bf9d4c | |
parent | 99c9cbc8f52a7f7da6c82a0a43eda9144e0b6452 (diff) | |
download | ghostpdl-openjpeg-update-20160927.tar.gz |
OpenJPEG allocation fixes.openjpeg-update-20160927
The old version of openjpeg allocates using malloc/free.
The new version of openjpeg allocates via opj_malloc (and co).
We can capture these and pass them down to our own allocators,
but we cannot get openjpeg to pass us a gs_memory_t * to use.
We therefore resort to using a static to hold 'the current
gs_memory_t *' before we call openjpeg. To keep this threadsafe
we add some private data to the gslibctx, which the openjpeg
implementation can use to hold a lock.
We add calls to both jpx decode implementations to init this
private data (where the luratech implementation is null).
-rw-r--r-- | base/gslibctx.c | 9 | ||||
-rw-r--r-- | base/gslibctx.h | 6 | ||||
-rw-r--r-- | base/sjpx_luratech.c | 9 | ||||
-rw-r--r-- | base/sjpx_openjpeg.c | 178 |
4 files changed, 198 insertions, 4 deletions
diff --git a/base/gslibctx.c b/base/gslibctx.c index fa4432a85..eaa04580f 100644 --- a/base/gslibctx.c +++ b/base/gslibctx.c @@ -175,7 +175,7 @@ int gs_lib_ctx_init( gs_memory_t *mem ) /* Initialise the underlying CMS. */ if (gscms_create(mem)) { - +Failure: gs_free_object(mem, mem->gs_lib_ctx->default_device_list, "gs_lib_ctx_fin"); @@ -183,6 +183,12 @@ int gs_lib_ctx_init( gs_memory_t *mem ) mem->gs_lib_ctx = NULL; return -1; } + + /* Initialise any lock required for the jpx codec */ + if (sjpxd_create(mem)) { + gscms_destroy(mem); + goto Failure; + } gp_get_realtime(pio->real_time_0); @@ -214,6 +220,7 @@ void gs_lib_ctx_fin(gs_memory_t *mem) ctx = mem->gs_lib_ctx; ctx_mem = ctx->memory; + sjpxd_destroy(mem); gscms_destroy(ctx_mem); gs_free_object(ctx_mem, ctx->profiledir, "gs_lib_ctx_fin"); diff --git a/base/gslibctx.h b/base/gslibctx.h index 84ec205f2..7a4e110ba 100644 --- a/base/gslibctx.h +++ b/base/gslibctx.h @@ -85,6 +85,7 @@ typedef struct gs_lib_ctx_s char *default_device_list; int gcsignal; int scanconverter; + void *sjpxd_private; /* optional for use of jpx codec */ } gs_lib_ctx_t; enum { @@ -135,4 +136,9 @@ gs_lib_ctx_get_default_device_list(const gs_memory_t *mem, char** dev_list_str, #define IS_LIBCTX_STDOUT(mem, f) (f == mem->gs_lib_ctx->fstdout) #define IS_LIBCTX_STDERR(mem, f) (f == mem->gs_lib_ctx->fstderr) +/* Functions to init/fin JPX decoder libctx entry */ +int sjpxd_create(gs_memory_t *mem); + +void sjpxd_destroy(gs_memory_t *mem); + #endif /* GSLIBCTX_H */ diff --git a/base/sjpx_luratech.c b/base/sjpx_luratech.c index a2f1fad3b..8488cc6d4 100644 --- a/base/sjpx_luratech.c +++ b/base/sjpx_luratech.c @@ -1076,6 +1076,15 @@ s_jpxe_release(stream_state *ss) gs_free_object(state->memory->non_gc_memory, state->inbuf, "s_jpxe_release(inbuf)"); } +int sjpxd_create(gs_memory_t *mem) +{ + return 0; +} + +void sjpxd_destroy(gs_memory_t *mem) +{ +} + /* encoder stream template */ const stream_template s_jpxe_template = { &st_jpxe_state, diff --git a/base/sjpx_openjpeg.c b/base/sjpx_openjpeg.c index cd52ccaad..e8d919a5d 100644 --- a/base/sjpx_openjpeg.c +++ b/base/sjpx_openjpeg.c @@ -22,6 +22,144 @@ #include "gdebug.h" #include "strimpl.h" #include "sjpx_openjpeg.h" +#include "gxsync.h" +#include "assert_.h" +#include "opj_malloc.h" + +/* Some locking to get around the criminal lack of context + * in the openjpeg library. */ +static gs_memory_t *opj_memory; + +int sjpxd_create(gs_memory_t *mem) +{ +#if !defined(SHARE_JPX) || (SHARE_JPX == 0) + gs_lib_ctx_t *ctx = mem->gs_lib_ctx; + + ctx->sjpxd_private = gx_monitor_label(gx_monitor_alloc(mem), "sjpxd_monitor"); + if (ctx->sjpxd_private == NULL) + return gs_error_VMerror; +#endif + return 0; +} + +void sjpxd_destroy(gs_memory_t *mem) +{ +#if !defined(SHARE_JPX) || (SHARE_JPX == 0) + gs_lib_ctx_t *ctx = mem->gs_lib_ctx; + + gx_monitor_free((gx_monitor_t *)ctx->sjpxd_private); + ctx->sjpxd_private = NULL; +#endif +} + +static int opj_lock(gs_memory_t *mem) +{ +#if !defined(SHARE_JPX) || (SHARE_JPX == 0) + gs_lib_ctx_t *ctx = mem->gs_lib_ctx; + int ret; + + ret = gx_monitor_enter((gx_monitor_t *)ctx->sjpxd_private); + assert(opj_memory == NULL); + opj_memory = mem->non_gc_memory; + return ret; +#else + return 0; +#endif +} + +static int opj_unlock(gs_memory_t *mem) +{ +#if !defined(SHARE_JPX) || (SHARE_JPX == 0) + gs_lib_ctx_t *ctx = mem->gs_lib_ctx; + + assert(opj_memory != NULL); + opj_memory = NULL; + return gx_monitor_leave((gx_monitor_t *)ctx->sjpxd_private); +#else + return 0; +#endif +} + +#if !defined(SHARE_JPX) || (SHARE_JPX == 0) +/* Allocation routines that use the memory pointer given above */ +void *opj_malloc(size_t size) +{ + if (size == 0) + return NULL; + + assert(opj_memory != NULL); + + return (void *)gs_alloc_bytes(opj_memory, size, "opj_malloc"); +} + +void *opj_calloc(size_t n, size_t size) +{ + void *ptr; + + /* FIXME: Check for overflow? */ + size *= n; + + ptr = opj_malloc(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void *opj_realloc(void *ptr, size_t size) +{ + if (ptr == NULL) + return opj_malloc(size); + + if (size == 0) + { + opj_free(ptr); + return NULL; + } + + return gs_resize_object(opj_memory, ptr, size, "opj_malloc"); +} + +void opj_free(void *ptr) +{ + gs_free_object(opj_memory, ptr, "opj_malloc"); +} + +void * opj_aligned_malloc(size_t size) +{ + uint8_t *ptr; + int off; + + if (size == 0) + return NULL; + + size += 16 + sizeof(uint8_t); + ptr = opj_malloc(size); + if (ptr == NULL) + return NULL; + off = 16-(((int)(intptr_t)ptr) & 15); + ptr[off-1] = off; + return ptr + off; +} + +void opj_aligned_free(void* ptr_) +{ + uint8_t *ptr = (uint8_t *)ptr_; + uint8_t off; + if (ptr == NULL) + return; + + off = ptr[-1]; + opj_free((void *)(((unsigned char *)ptr) - off)); +} + +#if 0 +/* UNUSED currently, and moderately tricky, so deferred until required */ +void * opj_aligned_realloc(void *ptr, size_t size) +{ + return opj_realloc(ptr, size); +} +#endif +#endif gs_private_st_simple(st_jpxd_state, stream_jpxd_state, "JPXDecode filter state"); /* creates a gc object for our state, @@ -536,11 +674,17 @@ s_opjd_process(stream_state * ss, stream_cursor_read * pr, { stream_jpxd_state *const state = (stream_jpxd_state *) ss; long in_size = pr->limit - pr->ptr; + int locked = 0; + int code; if (in_size > 0) { /* buffer available data */ - int code = s_opjd_accumulate_input(state, pr); + code = opj_lock(ss->memory); + if (code < 0) return code; + locked = 1; + + code = s_opjd_accumulate_input(state, pr); if (code < 0) return code; if (state->codec == NULL) { @@ -550,7 +694,11 @@ s_opjd_process(stream_state * ss, stream_cursor_read * pr, code = s_opjd_set_codec_format(ss, OPJ_CODEC_J2K); else code = s_opjd_set_codec_format(ss, OPJ_CODEC_JP2); - if (code < 0) return code; + if (code < 0) + { + (void)opj_unlock(ss->memory); + return code; + } } } @@ -558,7 +706,15 @@ s_opjd_process(stream_state * ss, stream_cursor_read * pr, { if (state->image == NULL) { - int ret = ERRC; + int ret; + + if (locked == 0) + { + ret = opj_lock(ss->memory); + if (ret < 0) return ret; + locked = 1; + } + #if OPJ_VERSION_MAJOR >= 2 && OPJ_VERSION_MINOR >= 1 opj_stream_set_user_data(state->stream, &(state->sb), NULL); #else @@ -567,7 +723,16 @@ s_opjd_process(stream_state * ss, stream_cursor_read * pr, opj_stream_set_user_data_length(state->stream, state->sb.size); ret = decode_image(state); if (ret != 0) + { + (void)opj_unlock(ss->memory); return ret; + } + } + + if (locked) + { + code = opj_unlock(ss->memory); + if (code < 0) return code; } /* copy out available data */ @@ -575,6 +740,9 @@ s_opjd_process(stream_state * ss, stream_cursor_read * pr, } + if (locked) + return opj_unlock(ss->memory); + /* ask for more data */ return 0; } @@ -600,6 +768,8 @@ s_opjd_release(stream_state *ss) if (state->codec == NULL) return; + (void)opj_lock(ss->memory); + /* free image data structure */ if (state->image) opj_image_destroy(state->image); @@ -612,6 +782,8 @@ s_opjd_release(stream_state *ss) if (state->codec) opj_destroy_codec(state->codec); + (void)opj_unlock(ss->memory); + /* free input buffer */ if (state->sb.data) gs_free_object(state->memory->non_gc_memory, state->sb.data, "s_opjd_release(sb.data)"); |