mirror of
https://github.com/libretro/RetroArch
synced 2025-02-24 18:39:59 +00:00
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:
parent
0ddb073784
commit
54db0fe515
@ -55,6 +55,7 @@ typedef struct
|
||||
uint8_t *directory_end;
|
||||
void *current_stream;
|
||||
uint8_t *compressed_data;
|
||||
uint8_t *decompressed_data;
|
||||
} zip_context_t;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -81,6 +83,11 @@ static void zip_context_free_stream(zip_context_t *zip_context)
|
||||
free(zip_context->compressed_data);
|
||||
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(
|
||||
@ -90,9 +97,10 @@ static bool zlib_stream_decompress_data_to_file_init(
|
||||
zip_context_t *zip_context = (zip_context_t *)context;
|
||||
uint8_t local_header_buf[4];
|
||||
uint32_t offsetNL, offsetEL;
|
||||
int64_t offsetData;
|
||||
|
||||
/* 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 */
|
||||
zip_context->compressed_data = (uint8_t*)malloc(csize);
|
||||
@ -100,54 +108,50 @@ static bool zlib_stream_decompress_data_to_file_init(
|
||||
goto error;
|
||||
|
||||
/* 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)
|
||||
goto error;
|
||||
|
||||
offsetNL = read_le(local_header_buf, 2); /* file name 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 */
|
||||
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)
|
||||
goto error;
|
||||
|
||||
switch (cmode)
|
||||
{
|
||||
case ZIP_MODE_STORED:
|
||||
handle->data = zip_context->compressed_data;
|
||||
zip_context->decompressed_data = zip_context->compressed_data;
|
||||
zip_context->compressed_data = NULL;
|
||||
handle->data = zip_context->decompressed_data;
|
||||
return true;
|
||||
|
||||
case ZIP_MODE_DEFLATED:
|
||||
zip_context->current_stream = zlib_inflate_backend.stream_new();
|
||||
if (!zip_context->current_stream)
|
||||
goto error;
|
||||
|
||||
|
||||
if (zlib_inflate_backend.define)
|
||||
zlib_inflate_backend.define(zip_context->current_stream, "window_bits", (uint32_t)-MAX_WBITS);
|
||||
|
||||
handle->data = (uint8_t*)malloc(size);
|
||||
|
||||
if (!handle->data)
|
||||
|
||||
zip_context->decompressed_data = (uint8_t*)malloc(size);
|
||||
|
||||
if (!zip_context->decompressed_data)
|
||||
goto error;
|
||||
|
||||
|
||||
zlib_inflate_backend.set_in(zip_context->current_stream,
|
||||
zip_context->compressed_data, csize);
|
||||
zlib_inflate_backend.set_out(zip_context->current_stream,
|
||||
handle->data, size);
|
||||
zip_context->decompressed_data, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
error:
|
||||
if (handle->data)
|
||||
{
|
||||
free(handle->data);
|
||||
handle->data = NULL;
|
||||
}
|
||||
|
||||
zip_context_free_stream(zip_context);
|
||||
zip_context_free_stream(zip_context, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -170,14 +174,15 @@ static int zlib_stream_decompress_data_to_file_iterate(
|
||||
if (zstatus && !terror)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
|
||||
{
|
||||
/* error during stream processing */
|
||||
zip_context_free_stream(zip_context);
|
||||
zip_context_free_stream(zip_context, false);
|
||||
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);
|
||||
|
||||
/* 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)
|
||||
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.
|
||||
*/
|
||||
zip_context = (zip_context_t*)malloc(sizeof(zip_context_t) + (size_t)directory_size);
|
||||
zip_context->file = state->archive_file;
|
||||
zip_context->directory = (uint8_t*)(zip_context + 1);
|
||||
zip_context->directory_entry = zip_context->directory;
|
||||
zip_context->directory_end = zip_context->directory + (size_t)directory_size;
|
||||
zip_context->current_stream = NULL;
|
||||
zip_context->compressed_data = NULL;
|
||||
zip_context->file = state->archive_file;
|
||||
zip_context->directory = (uint8_t*)(zip_context + 1);
|
||||
zip_context->directory_entry = zip_context->directory;
|
||||
zip_context->directory_end = zip_context->directory + (size_t)directory_size;
|
||||
zip_context->current_stream = 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)
|
||||
{
|
||||
free(zip_context);
|
||||
@ -485,7 +491,7 @@ static int zip_parse_file_iterate_step(void *context,
|
||||
static void zip_parse_file_free(void *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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user