Fix memory leak

Properly release buffers for extracted files from ZIP
Use RETRO_VFS_SEEK_POSITION_START instead of SEEK_SET for filestream_seek
This commit is contained in:
Bernhard Schelling 2020-07-14 00:29:46 +09:00
parent 0ddb073784
commit 54db0fe515
1 changed files with 36 additions and 30 deletions

View File

@ -55,6 +55,7 @@ typedef struct
uint8_t *directory_end; uint8_t *directory_end;
void *current_stream; void *current_stream;
uint8_t *compressed_data; uint8_t *compressed_data;
uint8_t *decompressed_data;
} zip_context_t; } zip_context_t;
static INLINE uint32_t read_le(const uint8_t *data, unsigned size) static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
@ -69,7 +70,8 @@ static INLINE uint32_t read_le(const uint8_t *data, unsigned size)
return val; return val;
} }
static void zip_context_free_stream(zip_context_t *zip_context) static void zip_context_free_stream(
zip_context_t *zip_context, bool keep_decompressed)
{ {
if (zip_context->current_stream) if (zip_context->current_stream)
{ {
@ -81,6 +83,11 @@ static void zip_context_free_stream(zip_context_t *zip_context)
free(zip_context->compressed_data); free(zip_context->compressed_data);
zip_context->compressed_data = NULL; zip_context->compressed_data = NULL;
} }
if (zip_context->decompressed_data && !keep_decompressed)
{
free(zip_context->decompressed_data);
zip_context->decompressed_data = NULL;
}
} }
static bool zlib_stream_decompress_data_to_file_init( static bool zlib_stream_decompress_data_to_file_init(
@ -90,9 +97,10 @@ static bool zlib_stream_decompress_data_to_file_init(
zip_context_t *zip_context = (zip_context_t *)context; zip_context_t *zip_context = (zip_context_t *)context;
uint8_t local_header_buf[4]; uint8_t local_header_buf[4];
uint32_t offsetNL, offsetEL; uint32_t offsetNL, offsetEL;
int64_t offsetData;
/* free previous stream if left unfinished */ /* free previous stream if left unfinished */
zip_context_free_stream(zip_context); zip_context_free_stream(zip_context, false);
/* allocate memory for the compressed data */ /* allocate memory for the compressed data */
zip_context->compressed_data = (uint8_t*)malloc(csize); zip_context->compressed_data = (uint8_t*)malloc(csize);
@ -100,54 +108,50 @@ static bool zlib_stream_decompress_data_to_file_init(
goto error; goto error;
/* seek past most of the local directory header */ /* seek past most of the local directory header */
filestream_seek(zip_context->file, (int64_t)(size_t)cdata + 26, SEEK_SET); filestream_seek(zip_context->file, (int64_t)(size_t)cdata + 26, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(zip_context->file, local_header_buf, 4) != 4) if (filestream_read(zip_context->file, local_header_buf, 4) != 4)
goto error; goto error;
offsetNL = read_le(local_header_buf, 2); /* file name length */ offsetNL = read_le(local_header_buf, 2); /* file name length */
offsetEL = read_le(local_header_buf + 2, 2); /* extra field length */ offsetEL = read_le(local_header_buf + 2, 2); /* extra field length */
offsetData = (int64_t)(size_t)cdata + 26 + 4 + offsetNL + offsetEL;
/* skip over name and extra data */ /* skip over name and extra data */
filestream_seek(zip_context->file, offsetNL + offsetEL, SEEK_CUR); filestream_seek(zip_context->file, offsetData, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(zip_context->file, zip_context->compressed_data, csize) != csize) if (filestream_read(zip_context->file, zip_context->compressed_data, csize) != csize)
goto error; goto error;
switch (cmode) switch (cmode)
{ {
case ZIP_MODE_STORED: case ZIP_MODE_STORED:
handle->data = zip_context->compressed_data; zip_context->decompressed_data = zip_context->compressed_data;
zip_context->compressed_data = NULL; zip_context->compressed_data = NULL;
handle->data = zip_context->decompressed_data;
return true; return true;
case ZIP_MODE_DEFLATED: case ZIP_MODE_DEFLATED:
zip_context->current_stream = zlib_inflate_backend.stream_new(); zip_context->current_stream = zlib_inflate_backend.stream_new();
if (!zip_context->current_stream) if (!zip_context->current_stream)
goto error; goto error;
if (zlib_inflate_backend.define) if (zlib_inflate_backend.define)
zlib_inflate_backend.define(zip_context->current_stream, "window_bits", (uint32_t)-MAX_WBITS); zlib_inflate_backend.define(zip_context->current_stream, "window_bits", (uint32_t)-MAX_WBITS);
handle->data = (uint8_t*)malloc(size); zip_context->decompressed_data = (uint8_t*)malloc(size);
if (!handle->data) if (!zip_context->decompressed_data)
goto error; goto error;
zlib_inflate_backend.set_in(zip_context->current_stream, zlib_inflate_backend.set_in(zip_context->current_stream,
zip_context->compressed_data, csize); zip_context->compressed_data, csize);
zlib_inflate_backend.set_out(zip_context->current_stream, zlib_inflate_backend.set_out(zip_context->current_stream,
handle->data, size); zip_context->decompressed_data, size);
return true; return true;
} }
error: error:
if (handle->data) zip_context_free_stream(zip_context, false);
{
free(handle->data);
handle->data = NULL;
}
zip_context_free_stream(zip_context);
return false; return false;
} }
@ -170,14 +174,15 @@ static int zlib_stream_decompress_data_to_file_iterate(
if (zstatus && !terror) if (zstatus && !terror)
{ {
/* successfully decompressed entire file */ /* successfully decompressed entire file */
zip_context_free_stream(zip_context); zip_context_free_stream(zip_context, true);
handle->data = zip_context->decompressed_data;
return 1; return 1;
} }
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL) if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
{ {
/* error during stream processing */ /* error during stream processing */
zip_context_free_stream(zip_context); zip_context_free_stream(zip_context, false);
return -1; return -1;
} }
@ -367,7 +372,7 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
read_pos = MAX(read_pos - read_block + 21, 0); read_pos = MAX(read_pos - read_block + 21, 0);
/* Seek to read_pos and read read_block bytes. */ /* Seek to read_pos and read read_block bytes. */
filestream_seek(state->archive_file, read_pos, SEEK_SET); filestream_seek(state->archive_file, read_pos, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, footer_buf, read_block) != read_block) if (filestream_read(state->archive_file, footer_buf, read_block) != read_block)
return -1; return -1;
@ -392,14 +397,15 @@ static int zip_parse_file_init(file_archive_transfer_t *state,
* context and the entire directory, then read the directory. * context and the entire directory, then read the directory.
*/ */
zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size); zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
zip_context->file = state->archive_file; zip_context->file = state->archive_file;
zip_context->directory = (uint8_t*)(zip_context + 1); zip_context->directory = (uint8_t*)(zip_context + 1);
zip_context->directory_entry = zip_context->directory; zip_context->directory_entry = zip_context->directory;
zip_context->directory_end = zip_context->directory + (size_t)directory_size; zip_context->directory_end = zip_context->directory + (size_t)directory_size;
zip_context->current_stream = NULL; zip_context->current_stream = NULL;
zip_context->compressed_data = NULL; zip_context->compressed_data = NULL;
zip_context->decompressed_data = NULL;
filestream_seek(state->archive_file, directory_offset, SEEK_SET); filestream_seek(state->archive_file, directory_offset, RETRO_VFS_SEEK_POSITION_START);
if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size) if (filestream_read(state->archive_file, zip_context->directory, directory_size) != directory_size)
{ {
free(zip_context); free(zip_context);
@ -485,7 +491,7 @@ static int zip_parse_file_iterate_step(void *context,
static void zip_parse_file_free(void *context) static void zip_parse_file_free(void *context)
{ {
zip_context_t *zip_context = (zip_context_t *)context; zip_context_t *zip_context = (zip_context_t *)context;
zip_context_free_stream(zip_context); zip_context_free_stream(zip_context, false);
free(zip_context); free(zip_context);
} }