Skip to content

Commit e2e40c5

Browse files
committed
Fix memory leak in TiffEncode
* If setimage errors out, the tiff client state was not freed.
1 parent a9bcd7d commit e2e40c5

File tree

3 files changed

+25
-21
lines changed

3 files changed

+25
-21
lines changed

src/encode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,8 @@ PyImaging_LibTiffEncoderNew(PyObject *self, PyObject *args) {
703703
return NULL;
704704
}
705705

706+
encoder->cleanup = ImagingLibTiffEncodeCleanup;
707+
706708
num_core_tags = sizeof(core_tags) / sizeof(int);
707709
for (pos = 0; pos < tags_size; pos++) {
708710
item = PyList_GetItemRef(tags, pos);

src/libImaging/TiffDecode.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,27 @@ ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...) {
929929
return status;
930930
}
931931

932+
int
933+
ImagingLibTiffEncodeCleanup(ImagingCodecState state) {
934+
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
935+
TIFF *tiff = clientstate->tiff;
936+
937+
if (!tiff) {
938+
return 0;
939+
}
940+
// TIFFClose in libtiff calls tif_closeproc and TIFFCleanup
941+
if (clientstate->fp) {
942+
// Python will manage the closing of the file rather than libtiff
943+
// So only call TIFFCleanup
944+
TIFFCleanup(tiff);
945+
} else {
946+
// When tif_closeproc refers to our custom _tiffCloseProc though,
947+
// that is fine, as it does not close the file
948+
TIFFClose(tiff);
949+
}
950+
return 0;
951+
}
952+
932953
int
933954
ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int bytes) {
934955
/* One shot encoder. Encode everything to the tiff in the clientstate.
@@ -1010,16 +1031,6 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt
10101031
TRACE(("Encode Error, row %d\n", state->y));
10111032
state->errcode = IMAGING_CODEC_BROKEN;
10121033

1013-
// TIFFClose in libtiff calls tif_closeproc and TIFFCleanup
1014-
if (clientstate->fp) {
1015-
// Python will manage the closing of the file rather than libtiff
1016-
// So only call TIFFCleanup
1017-
TIFFCleanup(tiff);
1018-
} else {
1019-
// When tif_closeproc refers to our custom _tiffCloseProc though,
1020-
// that is fine, as it does not close the file
1021-
TIFFClose(tiff);
1022-
}
10231034
if (!clientstate->fp) {
10241035
free(clientstate->data);
10251036
}
@@ -1036,22 +1047,11 @@ ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8 *buffer, int byt
10361047
TRACE(("Error flushing the tiff"));
10371048
// likely reason is memory.
10381049
state->errcode = IMAGING_CODEC_MEMORY;
1039-
if (clientstate->fp) {
1040-
TIFFCleanup(tiff);
1041-
} else {
1042-
TIFFClose(tiff);
1043-
}
10441050
if (!clientstate->fp) {
10451051
free(clientstate->data);
10461052
}
10471053
return -1;
10481054
}
1049-
TRACE(("Closing \n"));
1050-
if (clientstate->fp) {
1051-
TIFFCleanup(tiff);
1052-
} else {
1053-
TIFFClose(tiff);
1054-
}
10551055
// reset the clientstate metadata to use it to read out the buffer.
10561056
clientstate->loc = 0;
10571057
clientstate->size = clientstate->eof; // redundant?

src/libImaging/TiffDecode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ ImagingLibTiffInit(ImagingCodecState state, int fp, uint32_t offset);
4040
extern int
4141
ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
4242
extern int
43+
ImagingLibTiffEncodeCleanup(ImagingCodecState state);
44+
extern int
4345
ImagingLibTiffMergeFieldInfo(
4446
ImagingCodecState state, TIFFDataType field_type, int key, int is_var_length
4547
);

0 commit comments

Comments
 (0)