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:
@@ -23,6 +23,7 @@
|
|||||||
#include "jinclude.h"
|
#include "jinclude.h"
|
||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
#include "jmemsys.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().
|
* here. It is later reallocated by jinit_c_master_control().
|
||||||
*/
|
*/
|
||||||
cinfo->master = (struct jpeg_comp_master *)
|
cinfo->master = (struct jpeg_comp_master *)
|
||||||
jpeg_get_small ((j_common_ptr) cinfo, sizeof(struct jpeg_comp_master));
|
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
|
||||||
MEMZERO(cinfo->master, sizeof(struct jpeg_comp_master));
|
sizeof(my_comp_master));
|
||||||
|
MEMZERO(cinfo->master, sizeof(my_comp_master));
|
||||||
|
|
||||||
cinfo->master->compress_profile = JCP_MAX_COMPRESSION;
|
cinfo->master->compress_profile = JCP_MAX_COMPRESSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
jcmaster.c
49
jcmaster.c
@@ -21,42 +21,7 @@
|
|||||||
#include "jpeglib.h"
|
#include "jpeglib.h"
|
||||||
#include "jpegcomp.h"
|
#include "jpegcomp.h"
|
||||||
#include "jmemsys.h"
|
#include "jmemsys.h"
|
||||||
|
#include "jcmaster.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;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -919,21 +884,13 @@ finish_pass_master (j_compress_ptr cinfo)
|
|||||||
GLOBAL(void)
|
GLOBAL(void)
|
||||||
jinit_c_master_control (j_compress_ptr cinfo, boolean transcode_only)
|
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.prepare_for_pass = prepare_for_pass;
|
||||||
master->pub.pass_startup = pass_startup;
|
master->pub.pass_startup = pass_startup;
|
||||||
master->pub.finish_pass = finish_pass_master;
|
master->pub.finish_pass = finish_pass_master;
|
||||||
master->pub.is_last_pass = FALSE;
|
master->pub.is_last_pass = FALSE;
|
||||||
|
master->pub.call_pass_startup = FALSE;
|
||||||
|
|
||||||
/* Validate parameters, determine derived values */
|
/* Validate parameters, determine derived values */
|
||||||
initial_setup(cinfo, transcode_only);
|
initial_setup(cinfo, transcode_only);
|
||||||
|
|||||||
47
jcmaster.h
Normal file
47
jcmaster.h
Normal 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;
|
||||||
Reference in New Issue
Block a user