T1 decoder: check code stream errors when predictable termination is enabled and emit a warning when errors are found

This commit is contained in:
Even Rouault 2017-07-26 21:39:50 +02:00
parent 5e795d90a1
commit 94c4b7300c
6 changed files with 76 additions and 11 deletions

View File

@ -300,6 +300,7 @@ void opj_mqc_init_enc(opj_mqc_t *mqc, OPJ_BYTE *bp)
assert(*(mqc->bp) != 0xff); assert(*(mqc->bp) != 0xff);
mqc->start = bp; mqc->start = bp;
mqc->end_of_byte_stream_counter = 0;
} }
void opj_mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d) void opj_mqc_encode(opj_mqc_t *mqc, OPJ_UINT32 d)
@ -513,6 +514,7 @@ void opj_mqc_init_dec(opj_mqc_t *mqc, OPJ_BYTE *bp, OPJ_UINT32 len,
/* See https://github.com/uclouvain/openjpeg/issues/921 */ /* See https://github.com/uclouvain/openjpeg/issues/921 */
opj_mqc_init_dec_common(mqc, bp, len, extra_writable_bytes); opj_mqc_init_dec_common(mqc, bp, len, extra_writable_bytes);
opj_mqc_setcurctx(mqc, 0); opj_mqc_setcurctx(mqc, 0);
mqc->end_of_byte_stream_counter = 0;
if (len == 0) { if (len == 0) {
mqc->c = 0xff << 16; mqc->c = 0xff << 16;
} else { } else {

View File

@ -78,6 +78,8 @@ typedef struct opj_mqc {
OPJ_UINT32 a; OPJ_UINT32 a;
/** number of bits already read or free to write */ /** number of bits already read or free to write */
OPJ_UINT32 ct; OPJ_UINT32 ct;
/* only used by decoder, to count the number of times a terminating 0xFF >0x8F marker is read */
OPJ_UINT32 end_of_byte_stream_counter;
/** pointer to the current position in the buffer */ /** pointer to the current position in the buffer */
OPJ_BYTE *bp; OPJ_BYTE *bp;
/** pointer to the start of the buffer */ /** pointer to the start of the buffer */

View File

@ -109,6 +109,7 @@ static INLINE OPJ_UINT32 opj_mqc_raw_decode(opj_mqc_t *mqc)
if (l_c > 0x8f) { \ if (l_c > 0x8f) { \
c += 0xff00; \ c += 0xff00; \
ct = 8; \ ct = 8; \
mqc->end_of_byte_stream_counter ++; \
} else { \ } else { \
mqc->bp++; \ mqc->bp++; \
c += l_c << 9; \ c += l_c << 9; \

View File

@ -189,7 +189,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
opj_tcd_cblk_dec_t* cblk, opj_tcd_cblk_dec_t* cblk,
OPJ_UINT32 orient, OPJ_UINT32 orient,
OPJ_UINT32 roishift, OPJ_UINT32 roishift,
OPJ_UINT32 cblksty); OPJ_UINT32 cblksty,
opj_event_mgr_t *p_manager,
opj_mutex_t* p_manager_mutex,
OPJ_BOOL check_pterm);
static OPJ_BOOL opj_t1_allocate_buffers(opj_t1_t *t1, static OPJ_BOOL opj_t1_allocate_buffers(opj_t1_t *t1,
OPJ_UINT32 w, OPJ_UINT32 w,
@ -1608,6 +1611,9 @@ typedef struct {
opj_tcd_tilecomp_t* tilec; opj_tcd_tilecomp_t* tilec;
opj_tccp_t* tccp; opj_tccp_t* tccp;
volatile OPJ_BOOL* pret; volatile OPJ_BOOL* pret;
opj_event_mgr_t *p_manager;
opj_mutex_t* p_manager_mutex;
OPJ_BOOL check_pterm;
} opj_t1_cblk_decode_processing_job_t; } opj_t1_cblk_decode_processing_job_t;
static void opj_t1_destroy_wrapper(void* t1) static void opj_t1_destroy_wrapper(void* t1)
@ -1654,7 +1660,10 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
cblk, cblk,
band->bandno, band->bandno,
(OPJ_UINT32)tccp->roishift, (OPJ_UINT32)tccp->roishift,
tccp->cblksty)) { tccp->cblksty,
job->p_manager,
job->p_manager_mutex,
job->check_pterm)) {
*(job->pret) = OPJ_FALSE; *(job->pret) = OPJ_FALSE;
opj_free(job); opj_free(job);
return; return;
@ -1730,7 +1739,10 @@ static void opj_t1_clbl_decode_processor(void* user_data, opj_tls_t* tls)
void opj_t1_decode_cblks(opj_thread_pool_t* tp, void opj_t1_decode_cblks(opj_thread_pool_t* tp,
volatile OPJ_BOOL* pret, volatile OPJ_BOOL* pret,
opj_tcd_tilecomp_t* tilec, opj_tcd_tilecomp_t* tilec,
opj_tccp_t* tccp opj_tccp_t* tccp,
opj_event_mgr_t *p_manager,
opj_mutex_t* p_manager_mutex,
OPJ_BOOL check_pterm
) )
{ {
OPJ_UINT32 resno, bandno, precno, cblkno; OPJ_UINT32 resno, bandno, precno, cblkno;
@ -1760,6 +1772,9 @@ void opj_t1_decode_cblks(opj_thread_pool_t* tp,
job->tilec = tilec; job->tilec = tilec;
job->tccp = tccp; job->tccp = tccp;
job->pret = pret; job->pret = pret;
job->p_manager_mutex = p_manager_mutex;
job->p_manager = p_manager;
job->check_pterm = check_pterm;
opj_thread_pool_submit_job(tp, opj_t1_clbl_decode_processor, job); opj_thread_pool_submit_job(tp, opj_t1_clbl_decode_processor, job);
if (!(*pret)) { if (!(*pret)) {
return; return;
@ -1777,7 +1792,10 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
opj_tcd_cblk_dec_t* cblk, opj_tcd_cblk_dec_t* cblk,
OPJ_UINT32 orient, OPJ_UINT32 orient,
OPJ_UINT32 roishift, OPJ_UINT32 roishift,
OPJ_UINT32 cblksty) OPJ_UINT32 cblksty,
opj_event_mgr_t *p_manager,
opj_mutex_t* p_manager_mutex,
OPJ_BOOL check_pterm)
{ {
opj_mqc_t *mqc = &(t1->mqc); /* MQC component */ opj_mqc_t *mqc = &(t1->mqc); /* MQC component */
@ -1858,6 +1876,32 @@ static OPJ_BOOL opj_t1_decode_cblk(opj_t1_t *t1,
opq_mqc_finish_dec(mqc); opq_mqc_finish_dec(mqc);
} }
if (check_pterm) {
if (mqc->bp + 2 < mqc->end) {
if (p_manager_mutex) {
opj_mutex_lock(p_manager_mutex);
}
opj_event_msg(p_manager, EVT_WARNING,
"PTERM check failure: %d remaining bytes in code block (%d used / %d)\n",
(int)(mqc->end - mqc->bp) - 2,
(int)(mqc->bp - mqc->start),
(int)(mqc->end - mqc->start));
if (p_manager_mutex) {
opj_mutex_unlock(p_manager_mutex);
}
} else if (mqc->end_of_byte_stream_counter > 2) {
if (p_manager_mutex) {
opj_mutex_lock(p_manager_mutex);
}
opj_event_msg(p_manager, EVT_WARNING,
"PTERM check failure: %d synthetized 0xFF markers read\n",
mqc->end_of_byte_stream_counter);
if (p_manager_mutex) {
opj_mutex_unlock(p_manager_mutex);
}
}
}
return OPJ_TRUE; return OPJ_TRUE;
} }

View File

@ -230,7 +230,10 @@ Decode the code-blocks of a tile
void opj_t1_decode_cblks(opj_thread_pool_t* tp, void opj_t1_decode_cblks(opj_thread_pool_t* tp,
volatile OPJ_BOOL* pret, volatile OPJ_BOOL* pret,
opj_tcd_tilecomp_t* tilec, opj_tcd_tilecomp_t* tilec,
opj_tccp_t* tccp); opj_tccp_t* tccp,
opj_event_mgr_t *p_manager,
opj_mutex_t* p_manager_mutex,
OPJ_BOOL check_pterm);

View File

@ -157,7 +157,8 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
opj_codestream_index_t *p_cstr_index, opj_codestream_index_t *p_cstr_index,
opj_event_mgr_t *p_manager); opj_event_mgr_t *p_manager);
static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd); static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd,
opj_event_mgr_t *p_manager);
static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd); static OPJ_BOOL opj_tcd_dwt_decode(opj_tcd_t *p_tcd);
@ -1421,8 +1422,7 @@ OPJ_BOOL opj_tcd_decode_tile(opj_tcd_t *p_tcd,
/*------------------TIER1-----------------*/ /*------------------TIER1-----------------*/
/* FIXME _ProfStart(PGROUP_T1); */ /* FIXME _ProfStart(PGROUP_T1); */
if if (! opj_tcd_t1_decode(p_tcd, p_manager)) {
(! opj_tcd_t1_decode(p_tcd)) {
return OPJ_FALSE; return OPJ_FALSE;
} }
/* FIXME _ProfStop(PGROUP_T1); */ /* FIXME _ProfStop(PGROUP_T1); */
@ -1681,16 +1681,27 @@ static OPJ_BOOL opj_tcd_t2_decode(opj_tcd_t *p_tcd,
return OPJ_TRUE; return OPJ_TRUE;
} }
static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd) static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd, opj_event_mgr_t *p_manager)
{ {
OPJ_UINT32 compno; OPJ_UINT32 compno;
opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles; opj_tcd_tile_t * l_tile = p_tcd->tcd_image->tiles;
opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps; opj_tcd_tilecomp_t* l_tile_comp = l_tile->comps;
opj_tccp_t * l_tccp = p_tcd->tcp->tccps; opj_tccp_t * l_tccp = p_tcd->tcp->tccps;
volatile OPJ_BOOL ret = OPJ_TRUE; volatile OPJ_BOOL ret = OPJ_TRUE;
OPJ_BOOL check_pterm = OPJ_FALSE;
opj_mutex_t* p_manager_mutex = NULL;
p_manager_mutex = opj_mutex_create();
/* Only enable PTERM check if we decode all layers */
if (p_tcd->tcp->num_layers_to_decode == p_tcd->tcp->numlayers &&
(l_tccp->cblksty & J2K_CCP_CBLKSTY_PTERM) != 0) {
check_pterm = OPJ_TRUE;
}
for (compno = 0; compno < l_tile->numcomps; ++compno) { for (compno = 0; compno < l_tile->numcomps; ++compno) {
opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp); opj_t1_decode_cblks(p_tcd->thread_pool, &ret, l_tile_comp, l_tccp,
p_manager, p_manager_mutex, check_pterm);
if (!ret) { if (!ret) {
break; break;
} }
@ -1699,7 +1710,9 @@ static OPJ_BOOL opj_tcd_t1_decode(opj_tcd_t *p_tcd)
} }
opj_thread_pool_wait_completion(p_tcd->thread_pool, 0); opj_thread_pool_wait_completion(p_tcd->thread_pool, 0);
if (p_manager_mutex) {
opj_mutex_destroy(p_manager_mutex);
}
return ret; return ret;
} }