From 044c22e12fc2160d1de31dcf37f769af2ddf7910 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 17 Feb 2020 13:41:26 -0600 Subject: [PATCH 01/12] Test: Honor CMAKE_CROSSCOMPILING_EMULATOR variable This CMake variable is intended to define a wrapper program for executing cross-compiled executables. However, CTest doesn't use CMAKE_CROSSCOMPILING_EMULATOR, because it isn't obvious which tests should be executed with the wrapper and which tests are scripts that don't need it. This commit manually prepends ${CMAKE_CROSSCOMPILING_EMULATOR} to all unit test command lines that execute a program built by the libjpeg-turbo build system. Thus, one can set CMAKE_CROSSCOMPILING_EMULATOR in a CMake toolchain file to (for instance) "qemu-{architecture} {qemu_arguments}") in order to execute all eligible unit tests using QEMU. --- CMakeLists.txt | 61 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e2d5bd61..473ff9623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -888,12 +888,18 @@ foreach(libtype ${TEST_LIBTYPES}) set(suffix -static) endif() if(WITH_TURBOJPEG) - add_test(tjunittest-${libtype} tjunittest${suffix}) - add_test(tjunittest-${libtype}-alloc tjunittest${suffix} -alloc) - add_test(tjunittest-${libtype}-yuv tjunittest${suffix} -yuv) - add_test(tjunittest-${libtype}-yuv-alloc tjunittest${suffix} -yuv -alloc) - add_test(tjunittest-${libtype}-yuv-nopad tjunittest${suffix} -yuv -noyuvpad) - add_test(tjunittest-${libtype}-bmp tjunittest${suffix} -bmp) + add_test(tjunittest-${libtype} + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix}) + add_test(tjunittest-${libtype}-alloc + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -alloc) + add_test(tjunittest-${libtype}-yuv + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -yuv) + add_test(tjunittest-${libtype}-yuv-alloc + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -yuv -alloc) + add_test(tjunittest-${libtype}-yuv-nopad + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -yuv -noyuvpad) + add_test(tjunittest-${libtype}-bmp + ${CMAKE_CROSSCOMPILING_EMULATOR} tjunittest${suffix} -bmp) set(MD5_PPM_GRAY_TILE 89d3ca21213d9d864b50b4e4e7de4ca6) set(MD5_PPM_420_8x8_TILE 847fceab15c5b7b911cb986cf0f71de3) @@ -918,22 +924,23 @@ foreach(libtype ${TEST_LIBTYPES}) ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm testout_tile.ppm) add_test(tjbench-${libtype}-tile - tjbench${suffix} testout_tile.ppm 95 -rgb -quiet -tile -benchtime 0.01 - -warmup 0) + ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} testout_tile.ppm 95 + -rgb -quiet -tile -benchtime 0.01 -warmup 0) set_tests_properties(tjbench-${libtype}-tile PROPERTIES DEPENDS tjbench-${libtype}-tile-cp) foreach(tile 8 16 32 64 128) add_test(tjbench-${libtype}-tile-gray-${tile}x${tile}-cmp - ${MD5CMP} ${MD5_PPM_GRAY_TILE} + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_GRAY_TILE} testout_tile_GRAY_Q95_${tile}x${tile}.ppm) foreach(subsamp 420 422) add_test(tjbench-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp - ${MD5CMP} ${MD5_PPM_${subsamp}_${tile}x${tile}_TILE} + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} + ${MD5_PPM_${subsamp}_${tile}x${tile}_TILE} testout_tile_${subsamp}_Q95_${tile}x${tile}.ppm) endforeach() add_test(tjbench-${libtype}-tile-444-${tile}x${tile}-cmp - ${MD5CMP} ${MD5_PPM_444_TILE} + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_444_TILE} testout_tile_444_Q95_${tile}x${tile}.ppm) foreach(subsamp gray 420 422 444) set_tests_properties(tjbench-${libtype}-tile-${subsamp}-${tile}x${tile}-cmp @@ -945,19 +952,22 @@ foreach(libtype ${TEST_LIBTYPES}) ${CMAKE_COMMAND} -E copy_if_different ${TESTIMAGES}/testorig.ppm testout_tilem.ppm) add_test(tjbench-${libtype}-tilem - tjbench${suffix} testout_tilem.ppm 95 -rgb -fastupsample -quiet -tile - -benchtime 0.01 -warmup 0) + ${CMAKE_CROSSCOMPILING_EMULATOR} tjbench${suffix} testout_tilem.ppm 95 + -rgb -fastupsample -quiet -tile -benchtime 0.01 -warmup 0) set_tests_properties(tjbench-${libtype}-tilem PROPERTIES DEPENDS tjbench-${libtype}-tilem-cp) add_test(tjbench-${libtype}-tile-420m-8x8-cmp - ${MD5CMP} ${MD5_PPM_420M_8x8_TILE} testout_tilem_420_Q95_8x8.ppm) + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_420M_8x8_TILE} + testout_tilem_420_Q95_8x8.ppm) add_test(tjbench-${libtype}-tile-422m-8x8-cmp - ${MD5CMP} ${MD5_PPM_422M_8x8_TILE} testout_tilem_422_Q95_8x8.ppm) + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5_PPM_422M_8x8_TILE} + testout_tilem_422_Q95_8x8.ppm) foreach(tile 16 32 64 128) foreach(subsamp 420 422) add_test(tjbench-${libtype}-tile-${subsamp}m-${tile}x${tile}-cmp - ${MD5CMP} ${MD5_PPM_${subsamp}M_TILE} + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} + ${MD5_PPM_${subsamp}M_TILE} testout_tilem_${subsamp}_Q95_${tile}x${tile}.ppm) endforeach() endforeach() @@ -975,9 +985,10 @@ foreach(libtype ${TEST_LIBTYPES}) macro(add_bittest PROG NAME ARGS OUTFILE INFILE MD5SUM) add_test(${PROG}-${libtype}-${NAME} - ${PROG}${suffix} ${ARGS} -outfile ${OUTFILE} ${INFILE}) + ${CMAKE_CROSSCOMPILING_EMULATOR} ${PROG}${suffix} ${ARGS} + -outfile ${OUTFILE} ${INFILE}) add_test(${PROG}-${libtype}-${NAME}-cmp - ${MD5CMP} ${MD5SUM} ${OUTFILE}) + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} ${MD5SUM} ${OUTFILE}) set_tests_properties(${PROG}-${libtype}-${NAME}-cmp PROPERTIES DEPENDS ${PROG}-${libtype}-${NAME}) if(${ARGC} GREATER 6) @@ -998,7 +1009,8 @@ foreach(libtype ${TEST_LIBTYPES}) ${MD5_PPM_RGB_ISLOW} cjpeg-${libtype}-rgb-islow) add_test(djpeg-${libtype}-rgb-islow-icc-cmp - ${MD5CMP} b06a39d730129122e85c1363ed1bbc9e testout_rgb_islow.icc) + ${CMAKE_CROSSCOMPILING_EMULATOR} ${MD5CMP} + b06a39d730129122e85c1363ed1bbc9e testout_rgb_islow.icc) set_tests_properties(djpeg-${libtype}-rgb-islow-icc-cmp PROPERTIES DEPENDS djpeg-${libtype}-rgb-islow) @@ -1216,7 +1228,7 @@ foreach(libtype ${TEST_LIBTYPES}) # Context rows: Yes Intra-iMCU row: No iMCU row prefetch: No ENT: prog huff add_test(cjpeg-${libtype}-420-islow-prog - cjpeg${suffix} -dct int -prog + ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog -outfile testout_420_islow_prog.jpg ${TESTIMAGES}/testorig.ppm) add_bittest(djpeg 420-islow-prog-crop62x62_71_71 "-dct;int;-crop;62x62+71+71;-ppm" @@ -1233,7 +1245,7 @@ foreach(libtype ${TEST_LIBTYPES}) # Context rows: No Intra-iMCU row: Yes ENT: huff add_test(cjpeg-${libtype}-444-islow - cjpeg${suffix} -dct int -sample 1x1 + ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -sample 1x1 -outfile testout_444_islow.jpg ${TESTIMAGES}/testorig.ppm) add_bittest(djpeg 444-islow-skip1_6 "-dct;int;-skip;1,6;-ppm" testout_444_islow_skip1,6.ppm testout_444_islow.jpg @@ -1241,7 +1253,7 @@ foreach(libtype ${TEST_LIBTYPES}) # Context rows: No Intra-iMCU row: No ENT: prog huff add_test(cjpeg-${libtype}-444-islow-prog - cjpeg${suffix} -dct int -prog -sample 1x1 + ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -prog -sample 1x1 -outfile testout_444_islow_prog.jpg ${TESTIMAGES}/testorig.ppm) add_bittest(djpeg 444-islow-prog-crop98x98_13_13 "-dct;int;-crop;98x98+13+13;-ppm" @@ -1251,8 +1263,9 @@ foreach(libtype ${TEST_LIBTYPES}) # Context rows: No Intra-iMCU row: No ENT: arith if(WITH_ARITH_ENC) add_test(cjpeg-${libtype}-444-islow-ari - cjpeg${suffix} -dct int -arithmetic -sample 1x1 - -outfile testout_444_islow_ari.jpg ${TESTIMAGES}/testorig.ppm) + ${CMAKE_CROSSCOMPILING_EMULATOR} cjpeg${suffix} -dct int -arithmetic + -sample 1x1 -outfile testout_444_islow_ari.jpg + ${TESTIMAGES}/testorig.ppm) if(WITH_ARITH_DEC) add_bittest(djpeg 444-islow-ari-crop37x37_0_0 "-dct;int;-crop;37x37+0+0;-ppm" From 42d679b9fc311532645f98a8e9bcfbb1779b5f89 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 17 Feb 2020 15:19:32 -0600 Subject: [PATCH 02/12] MIPS SIMD: Always honor JSIMD_FORCE* env vars Previously, these environment variables were not honored unless a 74K CPU was detected, but this detection doesn't work properly with QEMU's user mode emulation. With all other CPU types, libjpeg-turbo honors JSIMD_FORCE* regardless of CPU detection. --- simd/mips/jsimd.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/simd/mips/jsimd.c b/simd/mips/jsimd.c index 454cc99c6..790e91fc2 100644 --- a/simd/mips/jsimd.c +++ b/simd/mips/jsimd.c @@ -2,7 +2,7 @@ * jsimd_mips.c * * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2009-2011, 2014, 2016, 2018, D. R. Commander. + * Copyright (C) 2009-2011, 2014, 2016, 2018, 2020, D. R. Commander. * Copyright (C) 2013-2014, MIPS Technologies, Inc., California. * Copyright (C) 2015-2016, 2018, Matthieu Darbois. * @@ -31,7 +31,7 @@ static unsigned int simd_support = ~0; #if defined(__linux__) -LOCAL(int) +LOCAL(void) parse_proc_cpuinfo(const char *search_string) { const char *file_name = "/proc/cpuinfo"; @@ -45,13 +45,12 @@ parse_proc_cpuinfo(const char *search_string) if (strstr(cpuinfo_line, search_string) != NULL) { fclose(f); simd_support |= JSIMD_DSPR2; - return 1; + return; } } fclose(f); } /* Did not find string in the proc file, or not Linux ELF. */ - return 0; } #endif @@ -79,8 +78,7 @@ init_simd(void) /* We still have a chance to use MIPS DSPR2 regardless of globally used * -mdspr2 options passed to gcc by performing runtime detection via * /proc/cpuinfo parsing on linux */ - if (!parse_proc_cpuinfo("MIPS 74K")) - return; + parse_proc_cpuinfo("MIPS 74K"); #endif #ifndef NO_GETENV From ed7cab47d918cf048403ceb4297cd452d58176d4 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 17 Feb 2020 16:35:00 -0600 Subject: [PATCH 03/12] MIPS DSPr2: Fix compiler warning with -mdspr2 If -mdspr2 is passed to the compiler, __mips_dsp will be defined, and __mips_dsp_rev will be >= 2, so parse_proc_cpuinfo() will not be used. --- simd/mips/jsimd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simd/mips/jsimd.c b/simd/mips/jsimd.c index 790e91fc2..4cf7e2ca4 100644 --- a/simd/mips/jsimd.c +++ b/simd/mips/jsimd.c @@ -29,7 +29,7 @@ static unsigned int simd_support = ~0; -#if defined(__linux__) +#if !(defined(__MIPSEL__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2)) && defined(__linux__) LOCAL(void) parse_proc_cpuinfo(const char *search_string) From 035262a18d146c410728677ecc46c38e66a5e9ad Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 17 Feb 2020 18:03:10 -0600 Subject: [PATCH 04/12] MIPS DSPr2: Work around various 'make test' errors Referring to #408, this commit #ifdefs DSPr2 SIMD functions that only work on little endian processors, and it completely excludes jsimd_h2v1_downsample_dspr2() and jsimd_h2v2_downsample_dspr2(). The latter two functions fail with the TJBench tiling regression tests, most likely because the implementation of the functions predates those tests. --- simd/mips/jsimd.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/simd/mips/jsimd.c b/simd/mips/jsimd.c index 4cf7e2ca4..d2546eed3 100644 --- a/simd/mips/jsimd.c +++ b/simd/mips/jsimd.c @@ -29,7 +29,7 @@ static unsigned int simd_support = ~0; -#if !(defined(__MIPSEL__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2)) && defined(__linux__) +#if !(defined(__mips_dsp) && (__mips_dsp_rev >= 2)) && defined(__linux__) LOCAL(void) parse_proc_cpuinfo(const char *search_string) @@ -72,7 +72,7 @@ init_simd(void) simd_support = 0; -#if defined(__MIPSEL__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2) +#if defined(__mips_dsp) && (__mips_dsp_rev >= 2) simd_support |= JSIMD_DSPR2; #elif defined(__linux__) /* We still have a chance to use MIPS DSPR2 regardless of globally used @@ -338,8 +338,13 @@ jsimd_can_h2v2_downsample(void) if (sizeof(JDIMENSION) != 4) return 0; + /* FIXME: jsimd_h2v2_downsample_dspr2() fails some of the TJBench tiling + * regression tests, probably because the DSPr2 SIMD implementation predates + * those tests. */ +#if 0 if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -374,8 +379,13 @@ jsimd_can_h2v1_downsample(void) if (sizeof(JDIMENSION) != 4) return 0; + /* FIXME: jsimd_h2v1_downsample_dspr2() fails some of the TJBench tiling + * regression tests, probably because the DSPr2 SIMD implementation predates + * those tests. */ +#if 0 if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -439,8 +449,10 @@ jsimd_can_h2v1_upsample(void) if (sizeof(JDIMENSION) != 4) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -501,8 +513,10 @@ jsimd_can_h2v2_fancy_upsample(void) if (sizeof(JDIMENSION) != 4) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -518,8 +532,10 @@ jsimd_can_h2v1_fancy_upsample(void) if (sizeof(JDIMENSION) != 4) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -667,8 +683,10 @@ jsimd_can_convsamp(void) if (sizeof(DCTELEM) != 2) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -725,8 +743,10 @@ jsimd_can_fdct_islow(void) if (sizeof(DCTELEM) != 2) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -742,8 +762,10 @@ jsimd_can_fdct_ifast(void) if (sizeof(DCTELEM) != 2) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -870,8 +892,10 @@ jsimd_can_idct_4x4(void) if (sizeof(ISLOW_MULT_TYPE) != 2) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } @@ -1015,8 +1039,10 @@ jsimd_can_idct_ifast(void) if (IFAST_SCALE_BITS != 2) return 0; +#if defined(__MIPSEL__) if (simd_support & JSIMD_DSPR2) return 1; +#endif return 0; } From ecf5f9a96ad621e22b56d7f7c026eb0c639f4a08 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 18 Feb 2020 10:43:23 -0600 Subject: [PATCH 05/12] Bump version to 2.0.5; Document previous commit --- CMakeLists.txt | 2 +- ChangeLog.md | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 473ff9623..0c3ee49eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if(CMAKE_EXECUTABLE_SUFFIX) endif() project(libjpeg-turbo C) -set(VERSION 2.0.4) +set(VERSION 2.0.5) string(REPLACE "." ";" VERSION_TRIPLET ${VERSION}) list(GET VERSION_TRIPLET 0 VERSION_MAJOR) list(GET VERSION_TRIPLET 1 VERSION_MINOR) diff --git a/ChangeLog.md b/ChangeLog.md index 4d1219e55..3db2b4b8d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,14 @@ +2.0.5 +===== + +1. Worked around issues in the MIPS DSPr2 SIMD extensions that caused failures +in the libjpeg-turbo regression tests. Specifically, the +`jsimd_h2v1_downsample_dspr2()` and `jsimd_h2v2_downsample_dspr2()` functions +in the MIPS DSPr2 SIMD extensions are now disabled until/unless they can be +fixed, and other functions that are incompatible with big endian MIPS CPUs are +disabled when building libjpeg-turbo for such CPUs. + + 2.0.4 ===== From 8cc1277b69ba16bb2d3aef785efa4cb8988ec12c Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 24 Feb 2020 13:29:50 -0600 Subject: [PATCH 06/12] TJCompressor.compress(int): Fix YUV-to-JPEG error Due to an oversight, the TJCompressor.compress(int) method did not handle YUV source images. Fixes #413 --- ChangeLog.md | 5 +++++ java/org/libjpegturbo/turbojpeg/TJCompressor.java | 13 ++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 3db2b4b8d..d63ad90f6 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -8,6 +8,11 @@ in the MIPS DSPr2 SIMD extensions are now disabled until/unless they can be fixed, and other functions that are incompatible with big endian MIPS CPUs are disabled when building libjpeg-turbo for such CPUs. +2. Fixed an oversight in the `TJCompressor.compress(int)` method in the +TurboJPEG Java API that caused an error ("java.lang.IllegalStateException: No +source image is associated with this instance") when attempting to use that +method to compress a YUV image. + 2.0.4 ===== diff --git a/java/org/libjpegturbo/turbojpeg/TJCompressor.java b/java/org/libjpegturbo/turbojpeg/TJCompressor.java index 74e5db9cd..6d4830f5f 100644 --- a/java/org/libjpegturbo/turbojpeg/TJCompressor.java +++ b/java/org/libjpegturbo/turbojpeg/TJCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (C)2011-2015, 2018 D. R. Commander. All Rights Reserved. + * Copyright (C)2011-2015, 2018, 2020 D. R. Commander. All Rights Reserved. * Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -377,8 +377,15 @@ else if (srcBuf != null) { * #getCompressedSize} to obtain the size of the JPEG image. */ public byte[] compress(int flags) throws TJException { - checkSourceImage(); - byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)]; + byte[] buf; + if (srcYUVImage != null) { + buf = new byte[TJ.bufSize(srcYUVImage.getWidth(), + srcYUVImage.getHeight(), + srcYUVImage.getSubsamp())]; + } else { + checkSourceImage(); + buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)]; + } compress(buf, flags); return buf; } From a36deef5639b470d1223a5f29bf67c9800f2600e Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 2 Apr 2020 22:23:02 -0500 Subject: [PATCH 07/12] rdswitch.c: Eliminate spaces before semicolons (detected with a modified version of checkstyle) --- rdswitch.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rdswitch.c b/rdswitch.c index c50c33e75..886fec39b 100644 --- a/rdswitch.c +++ b/rdswitch.c @@ -338,8 +338,8 @@ set_quality_ratings(j_compress_ptr cinfo, char *arg, boolean force_baseline) #else q_scale_factor[tblno] = jpeg_quality_scaling(val); #endif - while (*arg && *arg++ != ',') /* advance to next segment of arg string */ - ; + while (*arg && *arg++ != ','); /* advance to next segment of arg + string */ } else { /* reached end of parameter, set remaining factors to last value */ #if JPEG_LIB_VERSION >= 70 @@ -378,8 +378,8 @@ set_quant_slots(j_compress_ptr cinfo, char *arg) return FALSE; } cinfo->comp_info[ci].quant_tbl_no = val; - while (*arg && *arg++ != ',') /* advance to next segment of arg string */ - ; + while (*arg && *arg++ != ','); /* advance to next segment of arg + string */ } else { /* reached end of parameter, set remaining components to last table */ cinfo->comp_info[ci].quant_tbl_no = val; @@ -412,8 +412,8 @@ set_sample_factors(j_compress_ptr cinfo, char *arg) } cinfo->comp_info[ci].h_samp_factor = val1; cinfo->comp_info[ci].v_samp_factor = val2; - while (*arg && *arg++ != ',') /* advance to next segment of arg string */ - ; + while (*arg && *arg++ != ','); /* advance to next segment of arg + string */ } else { /* reached end of parameter, set remaining components to 1x1 sampling */ cinfo->comp_info[ci].h_samp_factor = 1; From a2291b252de1413a13db61b21863ae7aea0946f3 Mon Sep 17 00:00:00 2001 From: Andrew Childs Date: Tue, 5 May 2020 14:38:39 +0900 Subject: [PATCH 08/12] Build: Add missing jpegtran-icc test dependency The jpegtran-icc test must run after the cjpeg-rgb-islow test, since the latter generates testout_rgb_islow.jpg. --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c3ee49eb..fe16d8e15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1015,7 +1015,8 @@ foreach(libtype ${TEST_LIBTYPES}) DEPENDS djpeg-${libtype}-rgb-islow) add_bittest(jpegtran icc "-copy;all;-icc;${TESTIMAGES}/test2.icc" - testout_rgb_islow2.jpg testout_rgb_islow.jpg ${MD5_JPEG_RGB_ISLOW2}) + testout_rgb_islow2.jpg testout_rgb_islow.jpg + ${MD5_JPEG_RGB_ISLOW2} cjpeg-${libtype}-rgb-islow) if(NOT WITH_12BIT) # CC: RGB->RGB565 SAMP: fullsize IDCT: islow ENT: huff From 3de15e0c344d11d4b90f4a47136467053eb2d09a Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 2 Jun 2020 14:15:37 -0500 Subject: [PATCH 09/12] rdppm.c: Fix buf overrun caused by bad binary PPM This extends the fix in 1e81b0c3ea26f4ea8f56de05367469333de64a9f to include binary PPM files with maximum values < 255, thus preventing a malformed binary PPM input file with those specifications from triggering an overrun of the rescale array and potentially crashing cjpeg, TJBench, or any program that uses the tjLoadImage() function. Fixes #433 --- ChangeLog.md | 14 ++++++++++---- rdppm.c | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index d63ad90f6..ab58b9bd0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,12 @@ TurboJPEG Java API that caused an error ("java.lang.IllegalStateException: No source image is associated with this instance") when attempting to use that method to compress a YUV image. +3. Fixed an issue in the PPM reader that caused a buffer overrun in cjpeg, +TJBench, or the `tjLoadImage()` function if one of the values in a binary +PPM/PGM input file exceeded the maximum value defined in the file's header and +that maximum value was less than 255. libjpeg-turbo 1.5.0 already included a +similar fix for binary PPM/PGM files with maximum values greater than 255. + 2.0.4 ===== @@ -578,10 +584,10 @@ application was linked against. 3. Fixed a couple of issues in the PPM reader that would cause buffer overruns in cjpeg if one of the values in a binary PPM/PGM input file exceeded the -maximum value defined in the file's header. libjpeg-turbo 1.4.2 already -included a similar fix for ASCII PPM/PGM files. Note that these issues were -not security bugs, since they were confined to the cjpeg program and did not -affect any of the libjpeg-turbo libraries. +maximum value defined in the file's header and that maximum value was greater +than 255. libjpeg-turbo 1.4.2 already included a similar fix for ASCII PPM/PGM +files. Note that these issues were not security bugs, since they were confined +to the cjpeg program and did not affect any of the libjpeg-turbo libraries. 4. Fixed an issue whereby attempting to decompress a JPEG file with a corrupt header using the `tjDecompressToYUV2()` function would cause the function to diff --git a/rdppm.c b/rdppm.c index 87bc33090..a8507b902 100644 --- a/rdppm.c +++ b/rdppm.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2009 by Bill Allombert, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015-2017, D. R. Commander. + * Copyright (C) 2015-2017, 2020, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -720,7 +720,7 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) /* On 16-bit-int machines we have to be careful of maxval = 65535 */ source->rescale = (JSAMPLE *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, - (size_t)(((long)maxval + 1L) * + (size_t)(((long)MAX(maxval, 255) + 1L) * sizeof(JSAMPLE))); half_maxval = maxval / 2; for (val = 0; val <= (long)maxval; val++) { From cf483eee49efdc85a5a414117fb220482e0bb7cb Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 3 Jun 2020 16:04:06 -0500 Subject: [PATCH 10/12] ChangeLog.md: List CVE ID fixed by previous commit --- ChangeLog.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ab58b9bd0..9d18672a7 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,11 +13,12 @@ TurboJPEG Java API that caused an error ("java.lang.IllegalStateException: No source image is associated with this instance") when attempting to use that method to compress a YUV image. -3. Fixed an issue in the PPM reader that caused a buffer overrun in cjpeg, -TJBench, or the `tjLoadImage()` function if one of the values in a binary -PPM/PGM input file exceeded the maximum value defined in the file's header and -that maximum value was less than 255. libjpeg-turbo 1.5.0 already included a -similar fix for binary PPM/PGM files with maximum values greater than 255. +3. Fixed an issue (CVE-2020-13790) in the PPM reader that caused a buffer +overrun in cjpeg, TJBench, or the `tjLoadImage()` function if one of the values +in a binary PPM/PGM input file exceeded the maximum value defined in the file's +header and that maximum value was less than 255. libjpeg-turbo 1.5.0 already +included a similar fix for binary PPM/PGM files with maximum values greater +than 255. 2.0.4 From b443c541b9a6fdcac214f9f003de0aa13e480ac1 Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 3 Jun 2020 16:08:08 -0500 Subject: [PATCH 11/12] ChangeLog.md: Add missing sub-header for 2.0.5 --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 9d18672a7..685da6900 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,8 @@ 2.0.5 ===== +### Significant changes relative to 2.0.4: + 1. Worked around issues in the MIPS DSPr2 SIMD extensions that caused failures in the libjpeg-turbo regression tests. Specifically, the `jsimd_h2v1_downsample_dspr2()` and `jsimd_h2v2_downsample_dspr2()` functions From ae87a958613b69628b92088b313ded0d4f59a716 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 16 Jun 2020 13:52:39 -0500 Subject: [PATCH 12/12] TurboJPEG: Make global error handling thread-safe ... on platforms that support thread-local storage. This currently includes all supported platforms except 32-bit macOS. Fixes #396 --- CMakeLists.txt | 15 +++++++++++++++ ChangeLog.md | 5 +++++ doc/html/group___turbo_j_p_e_g.html | 2 +- jconfigint.h.in | 3 +++ turbojpeg.c | 5 +++-- turbojpeg.h | 2 +- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe16d8e15..8656d7a71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -451,6 +451,21 @@ if(NOT INLINE_WORKS) endif() message(STATUS "INLINE = ${INLINE} (FORCE_INLINE = ${FORCE_INLINE})") +if(WITH_TURBOJPEG) + if(MSVC) + set(THREAD_LOCAL "__declspec(thread)") + else() + set(THREAD_LOCAL "__thread") + endif() + check_c_source_compiles("${THREAD_LOCAL} int i; int main(void) { i = 0; return i; }" HAVE_THREAD_LOCAL) + if(HAVE_THREAD_LOCAL) + message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}") + else() + message(WARNING "Thread-local storage is not available. The TurboJPEG API library's global error handler will not be thread-safe.") + unset(THREAD_LOCAL) + endif() +endif() + if(UNIX AND NOT APPLE) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/conftest.map "VERS_1 { global: *; };") set(CMAKE_REQUIRED_FLAGS diff --git a/ChangeLog.md b/ChangeLog.md index 685da6900..59fb2de96 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,6 +22,11 @@ header and that maximum value was less than 255. libjpeg-turbo 1.5.0 already included a similar fix for binary PPM/PGM files with maximum values greater than 255. +4. The TurboJPEG API library's global error handler, which is used in functions +such as `tjBufSize()` and `tjLoadImage()` that do not require a TurboJPEG +instance handle, is now thread-safe on platforms that support thread-local +storage. + 2.0.4 ===== diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html index 5d67d78a2..2ee145f63 100644 --- a/doc/html/group___turbo_j_p_e_g.html +++ b/doc/html/group___turbo_j_p_e_g.html @@ -2129,7 +2129,7 @@

Function Documentation

Returns a descriptive error message explaining why the last command failed.

Parameters
- +
handlea handle to a TurboJPEG compressor, decompressor, or transformer instance, or NULL if the error was generated by a global function (but note that retrieving the error message for a global function is not thread-safe.)
handlea handle to a TurboJPEG compressor, decompressor, or transformer instance, or NULL if the error was generated by a global function (but note that retrieving the error message for a global function is thread-safe only on platforms that support thread-local storage.)
diff --git a/jconfigint.h.in b/jconfigint.h.in index 55df05367..68cbc2a50 100644 --- a/jconfigint.h.in +++ b/jconfigint.h.in @@ -7,6 +7,9 @@ /* How to obtain function inlining. */ #define INLINE @INLINE@ +/* How to obtain thread-local storage */ +#define THREAD_LOCAL @THREAD_LOCAL@ + /* Define to the full name of this package. */ #define PACKAGE_NAME "@CMAKE_PROJECT_NAME@" diff --git a/turbojpeg.c b/turbojpeg.c index 6226bc9dd..e63d1134c 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2009-2019 D. R. Commander. All Rights Reserved. + * Copyright (C)2009-2020 D. R. Commander. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -43,6 +43,7 @@ #include "transupp.h" #include "./jpegcomp.h" #include "./cdjpeg.h" +#include "jconfigint.h" extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *, boolean); @@ -55,7 +56,7 @@ extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, /* Error handling (based on example in example.txt) */ -static char errStr[JMSG_LENGTH_MAX] = "No error"; +static THREAD_LOCAL char errStr[JMSG_LENGTH_MAX] = "No error"; struct my_error_mgr { struct jpeg_error_mgr pub; diff --git a/turbojpeg.h b/turbojpeg.h index 074f015f4..f3209dd34 100644 --- a/turbojpeg.h +++ b/turbojpeg.h @@ -1650,7 +1650,7 @@ DLLEXPORT void tjFree(unsigned char *buffer); * @param handle a handle to a TurboJPEG compressor, decompressor, or * transformer instance, or NULL if the error was generated by a global * function (but note that retrieving the error message for a global function - * is not thread-safe.) + * is thread-safe only on platforms that support thread-local storage.) * * @return a descriptive error message explaining why the last command failed. */