Fix double free of cinfo->master caused by the extension framework modifications

There was an oversight in the extension framework.  jpeg_start_compress() can
be called multiple times between the time that a compress structure is created
and the time it is destroyed.  If this happened, then the following sequence
would occur:

-- heap alloc of master struct within jpeg_create_compress()
-- heap free of master struct within jinit_c_master_control()
-- static alloc of extended master struct (JPOOL_IMAGE) within
   jinit_c_master_control()
-- free extended master struct in jpeg_finish_compress()
-- jinit_c_master_control() now sees that cinfo->master is set and tries to
   free it, even though it has already been freed.  Chaos ensues.

The fix involved breaking out the extended master struct into a header so that
jpeg_create_compress() can go ahead and allocate it to the correct size, thus
eliminating the need to free and reallocate it in jinit_c_master_control().
Further, the master struct is now created in the permanent pool, so it will
survive until the compression struct is destroyed.  Further,
jinit_c_master_control() now resets all fields in the master struct that
are not related to the extension parameters.
This commit is contained in:
DRC
2014-12-14 03:59:44 -06:00
parent 668bb847d5
commit f645002fb6
3 changed files with 55 additions and 48 deletions

View File

@@ -23,6 +23,7 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h"
#include "jcmaster.h"
/*
@@ -97,8 +98,10 @@ jpeg_CreateCompress (j_compress_ptr cinfo, int version, size_t structsize)
* here. It is later reallocated by jinit_c_master_control().
*/
cinfo->master = (struct jpeg_comp_master *)
jpeg_get_small ((j_common_ptr) cinfo, sizeof(struct jpeg_comp_master));
MEMZERO(cinfo->master, sizeof(struct jpeg_comp_master));
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
sizeof(my_comp_master));
MEMZERO(cinfo->master, sizeof(my_comp_master));
cinfo->master->compress_profile = JCP_MAX_COMPRESSION;
}

View File

@@ -21,42 +21,7 @@
#include "jpeglib.h"
#include "jpegcomp.h"
#include "jmemsys.h"
/* Private state */
typedef enum {
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass, /* data output pass */
trellis_pass /* trellis quantization pass */
} c_pass_type;
typedef struct {
struct jpeg_comp_master pub; /* public fields */
c_pass_type pass_type; /* the type of the current pass */
int pass_number; /* # of passes completed */
int total_passes; /* total # of passes needed */
int scan_number; /* current index in scan_info[] */
/* fields for scan optimisation */
int pass_number_scan_opt_base; /* pass number where scan optimization begins */
unsigned char * scan_buffer[64]; /* buffer for a given scan */
unsigned long scan_size[64]; /* size for a given scan */
int actual_Al[64]; /* actual value of Al used for a scan */
unsigned long best_cost; /* bit count for best frequency split */
int best_freq_split_idx_luma; /* index for best frequency split (luma) */
int best_freq_split_idx_chroma; /* index for best frequency split (chroma) */
int best_Al_luma; /* best value for Al found in scan search (luma) */
int best_Al_chroma; /* best value for Al found in scan search (luma) */
boolean interleave_chroma_dc; /* indicate whether to interleave chroma DC scans */
struct jpeg_destination_mgr * saved_dest; /* saved value of cinfo->dest */
} my_comp_master;
typedef my_comp_master * my_master_ptr;
#include "jcmaster.h"
/*
@@ -919,21 +884,13 @@ finish_pass_master (j_compress_ptr cinfo)
GLOBAL(void)
jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
{
my_master_ptr master;
my_master_ptr master = (my_master_ptr) cinfo->master;
master = (my_master_ptr)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
sizeof(my_comp_master));
if (cinfo->master) {
MEMCOPY(&master->pub, cinfo->master, sizeof(struct jpeg_comp_master));
jpeg_free_small((j_common_ptr) cinfo, cinfo->master,
sizeof(struct jpeg_comp_master));
}
cinfo->master = (struct jpeg_comp_master *) master;
master->pub.prepare_for_pass = prepare_for_pass;
master->pub.pass_startup = pass_startup;
master->pub.finish_pass = finish_pass_master;
master->pub.is_last_pass = FALSE;
master->pub.call_pass_startup = FALSE;
/* Validate parameters, determine derived values */
initial_setup(cinfo, transcode_only);

47
jcmaster.h Normal file
View File

@@ -0,0 +1,47 @@
/*
* jcmaster.h
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains the master control structures for the JPEG compressor.
*/
/* Private state */
typedef enum {
main_pass, /* input data, also do first output step */
huff_opt_pass, /* Huffman code optimization pass */
output_pass, /* data output pass */
trellis_pass /* trellis quantization pass */
} c_pass_type;
typedef struct {
struct jpeg_comp_master pub; /* public fields */
c_pass_type pass_type; /* the type of the current pass */
int pass_number; /* # of passes completed */
int total_passes; /* total # of passes needed */
int scan_number; /* current index in scan_info[] */
/* fields for scan optimisation */
int pass_number_scan_opt_base; /* pass number where scan optimization begins */
unsigned char * scan_buffer[64]; /* buffer for a given scan */
unsigned long scan_size[64]; /* size for a given scan */
int actual_Al[64]; /* actual value of Al used for a scan */
unsigned long best_cost; /* bit count for best frequency split */
int best_freq_split_idx_luma; /* index for best frequency split (luma) */
int best_freq_split_idx_chroma; /* index for best frequency split (chroma) */
int best_Al_luma; /* best value for Al found in scan search (luma) */
int best_Al_chroma; /* best value for Al found in scan search (luma) */
boolean interleave_chroma_dc; /* indicate whether to interleave chroma DC scans */
struct jpeg_destination_mgr * saved_dest; /* saved value of cinfo->dest */
} my_comp_master;
typedef my_comp_master * my_master_ptr;