mirror of
https://github.com/libjpeg-turbo/libjpeg-turbo.git
synced 2026-01-18 21:41:20 +01:00
Don't traverse linked list when saving a marker
If the calling application invokes jpeg_save_markers() to save a particular type of marker, then the save_marker() function will be invoked for every marker of that type that is encountered. Previously, only the head of the marker linked list was stored (in jpeg_decompress_struct), so save_marker() had to traverse the entire linked list before it could add a new marker to the tail of the list. That caused CPU usage to grow exponentially with the number of markers. Referring to #764, it is possible to create a JPEG image that contains an excessive number of markers. The specific reproducer that uncovered this issue is a specially-crafted 1-megabyte malformed JPEG image with tens of thousands of APP1 markers, which required approximately 30 seconds of CPU time (on a modern Intel processor) to process. However, it should also be possible to create a legitimate JPEG image that reproduces the issue (such as an image with tens of thousands of duplicate EXIF tags.) This commit introduces a new pointer (in jpeg_decomp_master, in order to preserve backward ABI compatibility) that is used to store the tail of the marker linked list whenever a marker is added to it. Thus, it is no longer necessary to traverse the list when adding a marker, and CPU usage will grow linearly rather than exponentially with the number of markers. Fixes #764
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
*
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1994-1997, Thomas G. Lane.
|
||||
* It was modified by The libjpeg-turbo Project to include only code relevant
|
||||
* to libjpeg-turbo.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2024, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -51,6 +51,7 @@ jpeg_abort(j_common_ptr cinfo)
|
||||
* A bit kludgy to do it here, but this is the most central place.
|
||||
*/
|
||||
((j_decompress_ptr)cinfo)->marker_list = NULL;
|
||||
((j_decompress_ptr)cinfo)->master->marker_list_end = NULL;
|
||||
} else {
|
||||
cinfo->global_state = CSTATE_START;
|
||||
}
|
||||
|
||||
12
jdmarker.c
12
jdmarker.c
@@ -4,7 +4,7 @@
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-1998, Thomas G. Lane.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2012, 2015, D. R. Commander.
|
||||
* Copyright (C) 2012, 2015, 2024, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
@@ -818,13 +818,11 @@ save_marker(j_decompress_ptr cinfo)
|
||||
/* Done reading what we want to read */
|
||||
if (cur_marker != NULL) { /* will be NULL if bogus length word */
|
||||
/* Add new marker to end of list */
|
||||
if (cinfo->marker_list == NULL) {
|
||||
cinfo->marker_list = cur_marker;
|
||||
if (cinfo->marker_list == NULL || cinfo->master->marker_list_end == NULL) {
|
||||
cinfo->marker_list = cinfo->master->marker_list_end = cur_marker;
|
||||
} else {
|
||||
jpeg_saved_marker_ptr prev = cinfo->marker_list;
|
||||
while (prev->next != NULL)
|
||||
prev = prev->next;
|
||||
prev->next = cur_marker;
|
||||
cinfo->master->marker_list_end->next = cur_marker;
|
||||
cinfo->master->marker_list_end = cur_marker;
|
||||
}
|
||||
/* Reset pointer & calc remaining data length */
|
||||
data = cur_marker->data;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Copyright (C) 1991-1997, Thomas G. Lane.
|
||||
* Modified 1997-2009 by Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2015-2016, D. R. Commander.
|
||||
* Copyright (C) 2015-2016, 2024, D. R. Commander.
|
||||
* Copyright (C) 2015, Google, Inc.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
@@ -158,6 +158,9 @@ struct jpeg_decomp_master {
|
||||
JDIMENSION first_MCU_col[MAX_COMPONENTS];
|
||||
JDIMENSION last_MCU_col[MAX_COMPONENTS];
|
||||
boolean jinit_upsampler_no_alloc;
|
||||
|
||||
/* Tail of list of saved markers */
|
||||
jpeg_saved_marker_ptr marker_list_end;
|
||||
};
|
||||
|
||||
/* Input control module */
|
||||
|
||||
Reference in New Issue
Block a user