From 381f9676b3bbeb846b7479b8bd1ff9eb6bbaaaa2 Mon Sep 17 00:00:00 2001 From: Stefan Weil Date: Mon, 28 Mar 2016 11:15:43 +0200 Subject: [PATCH] Support files with very large data size The maximum supported data size is a limiting factor for the maximum size of allowed images. As it is possible to allocate size_t bytes, this data type must also be used for the data size. This modification also fixes issue #432. That file is now decoded on 64 bit hosts with enough RAM, so the regression test had to be fixed. Until it is possible to use different test cases for 32 and 64 bit hosts, the test for issue #432 is disabled. Handle also a potential division by zero when l_data_size is 0. This fixes issue #733. Update also some comments in the test suite. Signed-off-by: Stefan Weil --- src/lib/openjp2/tcd.c | 33 ++++++++++++------------- src/lib/openjp2/tcd.h | 8 +++--- tests/nonregression/md5refs.txt | 1 + tests/nonregression/test_suite.ctest.in | 9 ++++--- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/lib/openjp2/tcd.c b/src/lib/openjp2/tcd.c index 7a5e2b44..cf0230e5 100644 --- a/src/lib/openjp2/tcd.c +++ b/src/lib/openjp2/tcd.c @@ -738,7 +738,7 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, /* room needed to store l_nb_code_blocks code blocks for a precinct*/ OPJ_UINT32 l_nb_code_blocks_size; /* size of data for a tile */ - OPJ_UINT32 l_data_size; + size_t l_data_size; l_cp = p_tcd->cp; l_tcp = &(l_cp->tcps[p_tile_no]); @@ -795,21 +795,21 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, /*fprintf(stderr, "\tTile compo border = %d,%d,%d,%d\n", l_tilec->x0, l_tilec->y0,l_tilec->x1,l_tilec->y1);*/ /* compute l_data_size with overflow check */ - l_data_size = (OPJ_UINT32)(l_tilec->x1 - l_tilec->x0); + l_data_size = (size_t)(l_tilec->x1 - l_tilec->x0); /* issue 733, l_data_size == 0U, probably something wrong should be checked before getting here */ if ((l_data_size > 0U) && - ((((OPJ_UINT32) - 1) / l_data_size) < (OPJ_UINT32)(l_tilec->y1 - + ((SIZE_MAX / l_data_size) < (size_t)(l_tilec->y1 - l_tilec->y0))) { opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); return OPJ_FALSE; } l_data_size = l_data_size * (OPJ_UINT32)(l_tilec->y1 - l_tilec->y0); - if ((((OPJ_UINT32) - 1) / (OPJ_UINT32)sizeof(OPJ_UINT32)) < l_data_size) { - opj_event_msg(manager, EVT_ERROR, "Not enough memory for tile data\n"); + if ((SIZE_MAX / sizeof(OPJ_UINT32)) < l_data_size) { + opj_event_msg(manager, EVT_ERROR, "Size of tile data exceeds system limits\n"); return OPJ_FALSE; } - l_data_size = l_data_size * (OPJ_UINT32)sizeof(OPJ_UINT32); + l_data_size = l_data_size * sizeof(OPJ_UINT32); l_tilec->numresolutions = l_tccp->numresolutions; if (l_tccp->numresolutions < l_cp->m_specific_param.m_dec.m_reduce) { l_tilec->minimum_num_resolutions = 1; @@ -824,15 +824,14 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, return OPJ_FALSE; } - l_data_size = l_tilec->numresolutions * (OPJ_UINT32)sizeof( - opj_tcd_resolution_t); + l_data_size = l_tilec->numresolutions * sizeof(opj_tcd_resolution_t); if (l_tilec->resolutions == 00) { l_tilec->resolutions = (opj_tcd_resolution_t *) opj_malloc(l_data_size); if (! l_tilec->resolutions) { return OPJ_FALSE; } - /*fprintf(stderr, "\tAllocate resolutions of tilec (opj_tcd_resolution_t): %d\n",l_data_size);*/ + /*fprintf(stderr, "\tAllocate resolutions of tilec (opj_tcd_resolution_t): %tu\n", l_data_size);*/ l_tilec->resolutions_size = l_data_size; memset(l_tilec->resolutions, 0, l_data_size); } else if (l_data_size > l_tilec->resolutions_size) { @@ -846,7 +845,7 @@ static INLINE OPJ_BOOL opj_tcd_init_tile(opj_tcd_t *p_tcd, OPJ_UINT32 p_tile_no, return OPJ_FALSE; } l_tilec->resolutions = new_resolutions; - /*fprintf(stderr, "\tReallocate data of tilec (int): from %d to %d x OPJ_UINT32\n", l_tilec->resolutions_size, l_data_size);*/ + /*fprintf(stderr, "\tReallocate data of tilec (int): from %d to %tu x OPJ_UINT32\n", l_tilec->resolutions_size, l_data_size);*/ memset(((OPJ_BYTE*) l_tilec->resolutions) + l_tilec->resolutions_size, 0, l_data_size - l_tilec->resolutions_size); l_tilec->resolutions_size = l_data_size; @@ -1187,14 +1186,14 @@ static OPJ_BOOL opj_tcd_code_block_enc_allocate(opj_tcd_cblk_enc_t * static OPJ_BOOL opj_tcd_code_block_enc_allocate_data(opj_tcd_cblk_enc_t * p_code_block) { - OPJ_UINT32 l_data_size; + size_t l_data_size; /* +1 is needed for https://github.com/uclouvain/openjpeg/issues/835 */ /* and actually +2 required for https://github.com/uclouvain/openjpeg/issues/982 */ /* TODO: is there a theoretical upper-bound for the compressed code */ /* block size ? */ - l_data_size = 2 + (OPJ_UINT32)((p_code_block->x1 - p_code_block->x0) * - (p_code_block->y1 - p_code_block->y0) * (OPJ_INT32)sizeof(OPJ_UINT32)); + l_data_size = 2 + ((size_t)(p_code_block->x1 - p_code_block->x0) * + (size_t)(p_code_block->y1 - p_code_block->y0) * sizeof(OPJ_UINT32)); if (l_data_size > p_code_block->data_size) { if (p_code_block->data) { @@ -1604,13 +1603,13 @@ OPJ_BOOL opj_tcd_update_tile_data(opj_tcd_t *p_tcd, static void opj_tcd_free_tile(opj_tcd_t *p_tcd) { - OPJ_UINT32 compno, resno, bandno, precno; + OPJ_UINT32 compno, bandno, precno; opj_tcd_tile_t *l_tile = 00; opj_tcd_tilecomp_t *l_tile_comp = 00; opj_tcd_resolution_t *l_res = 00; opj_tcd_band_t *l_band = 00; opj_tcd_precinct_t *l_precinct = 00; - OPJ_UINT32 l_nb_resolutions, l_nb_precincts; + OPJ_UINT32 l_nb_precincts; void (* l_tcd_code_block_deallocate)(opj_tcd_precinct_t *) = 00; if (! p_tcd) { @@ -1637,8 +1636,8 @@ static void opj_tcd_free_tile(opj_tcd_t *p_tcd) for (compno = 0; compno < l_tile->numcomps; ++compno) { l_res = l_tile_comp->resolutions; if (l_res) { - - l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t); + size_t resno; + size_t l_nb_resolutions = l_tile_comp->resolutions_size / sizeof(opj_tcd_resolution_t); for (resno = 0; resno < l_nb_resolutions; ++resno) { l_band = l_res->bands; for (bandno = 0; bandno < 3; ++bandno) { diff --git a/src/lib/openjp2/tcd.h b/src/lib/openjp2/tcd.h index bf3c457e..20f80080 100644 --- a/src/lib/openjp2/tcd.h +++ b/src/lib/openjp2/tcd.h @@ -82,7 +82,7 @@ typedef struct opj_tcd_cblk_enc { y1; /* dimension of the code-blocks : left upper corner (x0, y0) right low corner (x1,y1) */ OPJ_UINT32 numbps; OPJ_UINT32 numlenbits; - OPJ_UINT32 data_size; /* Size of allocated data buffer */ + size_t data_size; /* Size of allocated data buffer */ OPJ_UINT32 numpasses; /* number of pass already done for the code-blocks */ OPJ_UINT32 numpassesinlayers; /* number of passes in the layer */ @@ -190,15 +190,15 @@ typedef struct opj_tcd_tilecomp { /* resolutions information */ opj_tcd_resolution_t *resolutions; /* size of data for resolutions (in bytes) */ - OPJ_UINT32 resolutions_size; + size_t resolutions_size; /* data of the component */ OPJ_INT32 *data; /* if true, then need to free after usage, otherwise do not free */ OPJ_BOOL ownsData; /* we may either need to allocate this amount of data, or re-use image data and ignore this value */ - OPJ_UINT32 data_size_needed; + size_t data_size_needed; /* size of the data of the component */ - OPJ_UINT32 data_size; + size_t data_size; /* add fixed_quality */ OPJ_INT32 numpix; } opj_tcd_tilecomp_t; diff --git a/tests/nonregression/md5refs.txt b/tests/nonregression/md5refs.txt index a2cda422..bc711943 100644 --- a/tests/nonregression/md5refs.txt +++ b/tests/nonregression/md5refs.txt @@ -173,6 +173,7 @@ d5ecef537edf294af83826763c0cf860 issue411-ycc422.jp2_1.pgx 07480962d25b3d8cce18096648963c8a issue411-ycc420.jp2_0.pgx 149a69831b42401f20b8f7492ef99d97 issue411-ycc420.jp2_1.pgx ec8d1c99db9763a8ba489df4f41dda53 issue411-ycc420.jp2_2.pgx +895b5a311e96f458e3c058f2f50f4fa3 issue432.jp2_0.pgx 3c7ff2e4bdae849167be36589f32bcd5 issue458.jp2_0.pgx f004b48eafb2e52529cc9c7b6a3ff5d2 issue458.jp2_1.pgx 3127bd0a591d113c3c2428c8d2c14ec8 issue458.jp2_2.pgx diff --git a/tests/nonregression/test_suite.ctest.in b/tests/nonregression/test_suite.ctest.in index ffd964c2..3b27ec1e 100644 --- a/tests/nonregression/test_suite.ctest.in +++ b/tests/nonregression/test_suite.ctest.in @@ -1,4 +1,4 @@ -# This file list all the input commands of the tests run by the ctest command which +# This file lists all the input commands of the tests run by the ctest command which # are not related to the conformance files. # # For each line of this file (except line which begin with #) an opj_compress test or a @@ -9,7 +9,7 @@ # + For decoder related tests = dump, compare dump to base, (TODO: compare outpout decoding # image to base) # -# Line begin with ! should failed (should be used for bad jpeg2000 file which should be +# Lines beginning with ! should fail (should be used for bad jpeg2000 file which should be # gracefully rejected). Please add a short resume about why this file should be rejected. # # You can use @INPUT_NR_PATH@ and @TEMP_PATH@ cmake variable which refers to OPJ_DATA_ROOT @@ -350,7 +350,10 @@ opj_decompress -i @INPUT_NR_PATH@/issue411-ycc420.jp2 -o @TEMP_PATH@/issue411-yc # issue 429 (from pdfium fuzz engine) 0 entries in PCLR box. !opj_decompress -i @INPUT_NR_PATH@/issue429.jp2 -o @TEMP_PATH@/issue429.jp2.pgx # issue 432 (from pdfium fuzz engine) Overflow in tcd tilec data size computation. -!opj_decompress -i @INPUT_NR_PATH@/issue432.jp2 -o @TEMP_PATH@/issue432.jp2.pgx +# On hosts with 64 bit size_t, opj_decompress now works. +# On hosts with 32 bit size_t, opj_decompress cannot handle this file. +# TODO: We need different test cases for both kinds of hosts. Don't run test until this works. +## opj_decompress -i @INPUT_NR_PATH@/issue432.jp2 -o @TEMP_PATH@/issue432.jp2.pgx # issue 427 image width is 0 !opj_decompress -i @INPUT_NR_PATH@/issue427-null-image-size.jp2 -o @TEMP_PATH@/issue427-null-image-size.jp2.pgx # issue 427 illegal tile offset