Merge pull request #221 from wiredfool/jpeg_memoryleak

Jpeg Decode memory leak fix.
This commit is contained in:
Alex Clark ☺ 2013-05-16 12:42:45 -07:00
commit aea9570a2c
4 changed files with 252 additions and 211 deletions

View File

@ -209,6 +209,10 @@ class ImageFile(Image.Image):
if not s: # truncated jpeg if not s: # truncated jpeg
self.tile = [] self.tile = []
# JpegDecode needs to clean things up here either way
# If we don't destroy the decompressor, we have a memory leak.
d.cleanup()
if LOAD_TRUNCATED_IMAGES: if LOAD_TRUNCATED_IMAGES:
break break
else: else:

View File

@ -48,6 +48,7 @@ typedef struct {
PyObject_HEAD PyObject_HEAD
int (*decode)(Imaging im, ImagingCodecState state, int (*decode)(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
int (*cleanup)(ImagingCodecState state);
struct ImagingCodecStateInstance state; struct ImagingCodecStateInstance state;
Imaging im; Imaging im;
PyObject* lock; PyObject* lock;
@ -89,6 +90,9 @@ PyImaging_DecoderNew(int contextsize)
decoder->lock = NULL; decoder->lock = NULL;
decoder->im = NULL; decoder->im = NULL;
/* Initialize the cleanup function pointer */
decoder->cleanup = NULL;
return decoder; return decoder;
} }
@ -115,6 +119,20 @@ _decode(ImagingDecoderObject* decoder, PyObject* args)
return Py_BuildValue("ii", status, decoder->state.errcode); return Py_BuildValue("ii", status, decoder->state.errcode);
} }
static PyObject*
_decode_cleanup(ImagingDecoderObject* decoder, PyObject* args)
{
int status = 0;
if (decoder->cleanup){
status = decoder->cleanup(&decoder->state);
}
return Py_BuildValue("i", status);
}
extern Imaging PyImaging_AsImaging(PyObject *op); extern Imaging PyImaging_AsImaging(PyObject *op);
static PyObject* static PyObject*
@ -178,6 +196,7 @@ _setimage(ImagingDecoderObject* decoder, PyObject* args)
static struct PyMethodDef methods[] = { static struct PyMethodDef methods[] = {
{"decode", (PyCFunction)_decode, 1}, {"decode", (PyCFunction)_decode, 1},
{"cleanup", (PyCFunction)_decode_cleanup, 1},
{"setimage", (PyCFunction)_setimage, 1}, {"setimage", (PyCFunction)_setimage, 1},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -755,6 +774,7 @@ PyImaging_JpegDecoderNew(PyObject* self, PyObject* args)
return NULL; return NULL;
decoder->decode = ImagingJpegDecode; decoder->decode = ImagingJpegDecode;
decoder->cleanup = ImagingJpegDecodeCleanup;
strncpy(((JPEGSTATE*)decoder->state.context)->rawmode, rawmode, 8); strncpy(((JPEGSTATE*)decoder->state.context)->rawmode, rawmode, 8);
strncpy(((JPEGSTATE*)decoder->state.context)->jpegmode, jpegmode, 8); strncpy(((JPEGSTATE*)decoder->state.context)->jpegmode, jpegmode, 8);

View File

@ -417,6 +417,8 @@ extern int ImagingHexDecode(Imaging im, ImagingCodecState state,
#ifdef HAVE_LIBJPEG #ifdef HAVE_LIBJPEG
extern int ImagingJpegDecode(Imaging im, ImagingCodecState state, extern int ImagingJpegDecode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
extern int ImagingJpegDecodeCleanup(ImagingCodecState state);
extern int ImagingJpegEncode(Imaging im, ImagingCodecState state, extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
UINT8* buffer, int bytes); UINT8* buffer, int bytes);
#endif #endif

View File

@ -263,5 +263,20 @@ ImagingJpegDecode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
} }
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
int ImagingJpegDecodeCleanup(ImagingCodecState state){
/* called to fee the decompression engine when the decode terminates
due to a corrupt or truncated image
*/
JPEGSTATE* context = (JPEGSTATE*) state->context;
/* Clean up */
jpeg_destroy_decompress(&context->cinfo);
return -1;
}
#endif #endif