From a219fd13b086d9af53de37a5e1bfec985cda60fc Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 12 May 2021 10:58:59 -0500 Subject: [PATCH 01/56] GitHub bug-report.md: "master" branch --> "main" --- .github/ISSUE_TEMPLATE/bug-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index a2a5febb..0943d8ff 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -31,7 +31,7 @@ assignees: dcommander **Platform(s) (compiler version, operating system version, CPU) on which the bug was observed:** -**libjpeg-turbo release(s), commit(s), or branch(es) in which the bug was observed (always test the tip of the master branch or the latest [stable pre-release](https://libjpeg-turbo.org/DeveloperInfo/PreReleases) to verify that the bug hasn't already been fixed):** +**libjpeg-turbo release(s), commit(s), or branch(es) in which the bug was observed (always test the tip of the main branch or the latest [stable pre-release](https://libjpeg-turbo.org/DeveloperInfo/PreReleases) to verify that the bug hasn't already been fixed):** **If the bug is a regression, the specific commit that introduced the regression (use `git bisect` to determine this):** From 3932190c2e70f734045baadbdfdc9147a3ead028 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 17 May 2021 13:05:16 -0500 Subject: [PATCH 02/56] Fix build w/ non-GCC-compatible Un*x/Arm compilers Regression introduced by d2c407995992be1f128704ae2479adfd7906c158 Closes #519 --- CMakeLists.txt | 2 +- ChangeLog.md | 9 +++++++++ jchuff.c | 5 +++-- jcphuff.c | 5 +++-- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a198fd..3272e31a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if(CMAKE_EXECUTABLE_SUFFIX) endif() project(libjpeg-turbo C) -set(VERSION 2.1.0) +set(VERSION 2.1.1) 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 498b8f27..5ecbf3b5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,12 @@ +2.1.1 +===== + +### Significant changes relative to 2.1.0 + +1. Fixed a regression introduced in 2.1.0 that caused build failures with +non-GCC-compatible compilers for Un*x/Arm platforms. + + 2.1.0 ===== diff --git a/jchuff.c b/jchuff.c index 2bce767e..8ff817b1 100644 --- a/jchuff.c +++ b/jchuff.c @@ -44,8 +44,9 @@ * flags (this defines __thumb__). */ -#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \ - defined(_M_ARM64) +/* NOTE: Both GCC and Clang define __GNUC__ */ +#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \ + defined(_M_ARM) || defined(_M_ARM64) #if !defined(__thumb__) || defined(__thumb2__) #define USE_CLZ_INTRINSIC #endif diff --git a/jcphuff.c b/jcphuff.c index bd14fc27..9bf96124 100644 --- a/jcphuff.c +++ b/jcphuff.c @@ -52,8 +52,9 @@ * flags (this defines __thumb__). */ -#if defined(__arm__) || defined(__aarch64__) || defined(_M_ARM) || \ - defined(_M_ARM64) +/* NOTE: Both GCC and Clang define __GNUC__ */ +#if (defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))) || \ + defined(_M_ARM) || defined(_M_ARM64) #if !defined(__thumb__) || defined(__thumb2__) #define USE_CLZ_INTRINSIC #endif From 5135c2e25d923b3737a92a686b124759883dd209 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 28 May 2021 12:51:53 -0500 Subject: [PATCH 03/56] Build: Use PIC for jsimd_none.o in shared libs In theory, all objects that will be included in a Un*x shared library must be built using PIC. In practice, most compilers don't require PIC to be explicitly specified for jsimd_none.o, either because the compiler automatically enables PIC in all cases (Ubuntu) or because the size of the generated object is too small. But some rare compilers do require PIC to be explicitly specified for jsimd_none.o. Fixes #520 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3272e31a..53e59c41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -582,6 +582,9 @@ if(WITH_SIMD) endif() else() add_library(simd OBJECT jsimd_none.c) + if(NOT WIN32 AND (CMAKE_POSITION_INDEPENDENT_CODE OR ENABLE_SHARED)) + set_target_properties(simd PROPERTIES POSITION_INDEPENDENT_CODE 1) + endif() endif() if(WITH_JAVA) From 1a1fb615db39880044b789bdb36b351865d9ec4a Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 18 Jun 2021 09:46:03 -0500 Subject: [PATCH 04/56] ChangeLog.md: List CVE ID fixed by c76f4a08 Referring to #527, the security community did not assign this CVE ID until more than 8 months after the fix for the issue was released. By the time they assigned the ID, libjpeg-turbo already had two production releases containing the fix. This calls into question the usefulness of assigning a CVE ID to the issue, particularly given that the buffer overrun in question was fully contained in the stack, not detectable with valgrind, and confined to lossless transformation (it did not affect JPEG compression or decompression.) https://vuldb.com/?id.176175 says that "the exploitability is told to be easy" but provides no clarification, and given that the author of that page does not seem to be aware that a fix for the issue has been available since early December of 2019, it calls into question the accuracy of everything else on the page. It would really be nice if the security community approached me about these things before wasting my time, but I guess it's my lot in life to modify a change log entry from 2019 to include a CVE ID from 2020. So it goes... --- ChangeLog.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5ecbf3b5..ea0f9031 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -293,15 +293,15 @@ JPEG images. This was known to cause a buffer overflow when attempting to decompress some such images using `tjDecompressToYUV2()` or `tjDecompressToYUVPlanes()`. -5. Fixed an issue, detected by ASan, whereby attempting to losslessly transform -a specially-crafted malformed JPEG image containing an extremely-high-frequency -coefficient block (junk image data that could never be generated by a -legitimate JPEG compressor) could cause the Huffman encoder's local buffer to -be overrun. (Refer to 1.4.0[9] and 1.4beta1[15].) Given that the buffer -overrun was fully contained within the stack and did not cause a segfault or -other user-visible errant behavior, and given that the lossless transformer -(unlike the decompressor) is not generally exposed to arbitrary data exploits, -this issue did not likely pose a security risk. +5. Fixed an issue (CVE-2020-17541), detected by ASan, whereby attempting to +losslessly transform a specially-crafted malformed JPEG image containing an +extremely-high-frequency coefficient block (junk image data that could never be +generated by a legitimate JPEG compressor) could cause the Huffman encoder's +local buffer to be overrun. (Refer to 1.4.0[9] and 1.4beta1[15].) Given that +the buffer overrun was fully contained within the stack and did not cause a +segfault or other user-visible errant behavior, and given that the lossless +transformer (unlike the decompressor) is not generally exposed to arbitrary +data exploits, this issue did not likely pose a security risk. 6. The Arm 64-bit (Armv8) Neon SIMD assembly code now stores constants in a separate read-only data section rather than in the text section, to support From 9df5786f05c8be702f5a896b231c6e057847c18b Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Sat, 26 Jun 2021 16:22:21 -0700 Subject: [PATCH 05/56] Fix -Wimplicit-fallthrough warnings with Clang The existing /*FALLTHROUGH*/ comments work with GCC but not Clang, so this commit adds a FALLTHROUGH macro that uses the 'fallthrough' attribute if the compiler supports it. Refer to https://bugs.chromium.org/p/chromium/issues/detail?id=995993 NOTE: All versions of GCC that support -Wimplicit-fallthrough also support the 'fallthrough' attribute, but certain other compilers (Oracle Solaris Studio, for instance) support /*FALLTHROUGH*/ but not the 'fallthrough' attribute. Thus, this commit retains the /*FALLTHROUGH*/ comments, which have existed in the libjpeg code base in some form since 1994 (libjpeg v5.) Closes #531 --- jcmaster.c | 2 +- jconfigint.h.in | 10 ++++++++++ jdapimin.c | 3 ++- jdmainct.c | 5 +++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/jcmaster.c b/jcmaster.c index 998dc40a..c2b26000 100644 --- a/jcmaster.c +++ b/jcmaster.c @@ -493,7 +493,7 @@ prepare_for_pass(j_compress_ptr cinfo) master->pass_type = output_pass; master->pass_number++; #endif - /*FALLTHROUGH*/ + FALLTHROUGH /*FALLTHROUGH*/ case output_pass: /* Do a data-output pass. */ /* We need not repeat per-scan setup if prior optimization pass did it. */ diff --git a/jconfigint.h.in b/jconfigint.h.in index 68cbc2a5..d087d7b5 100644 --- a/jconfigint.h.in +++ b/jconfigint.h.in @@ -32,3 +32,13 @@ #define HAVE_BITSCANFORWARD #endif #endif + +#if defined(__has_attribute) +#if __has_attribute(fallthrough) +#define FALLTHROUGH __attribute__((fallthrough)); +#else +#define FALLTHROUGH +#endif +#else +#define FALLTHROUGH +#endif diff --git a/jdapimin.c b/jdapimin.c index 21a41d2e..4609b132 100644 --- a/jdapimin.c +++ b/jdapimin.c @@ -23,6 +23,7 @@ #include "jinclude.h" #include "jpeglib.h" #include "jdmaster.h" +#include "jconfigint.h" /* @@ -308,7 +309,7 @@ jpeg_consume_input(j_decompress_ptr cinfo) /* Initialize application's data source module */ (*cinfo->src->init_source) (cinfo); cinfo->global_state = DSTATE_INHEADER; - /*FALLTHROUGH*/ + FALLTHROUGH /*FALLTHROUGH*/ case DSTATE_INHEADER: retcode = (*cinfo->inputctl->consume_input) (cinfo); if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ diff --git a/jdmainct.c b/jdmainct.c index 50301d6b..f466b259 100644 --- a/jdmainct.c +++ b/jdmainct.c @@ -18,6 +18,7 @@ #include "jinclude.h" #include "jdmainct.h" +#include "jconfigint.h" /* @@ -360,7 +361,7 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf, main_ptr->context_state = CTX_PREPARE_FOR_IMCU; if (*out_row_ctr >= out_rows_avail) return; /* Postprocessor exactly filled output buf */ - /*FALLTHROUGH*/ + FALLTHROUGH /*FALLTHROUGH*/ case CTX_PREPARE_FOR_IMCU: /* Prepare to process first M-1 row groups of this iMCU row */ main_ptr->rowgroup_ctr = 0; @@ -371,7 +372,7 @@ process_data_context_main(j_decompress_ptr cinfo, JSAMPARRAY output_buf, if (main_ptr->iMCU_row_ctr == cinfo->total_iMCU_rows) set_bottom_pointers(cinfo); main_ptr->context_state = CTX_PROCESS_IMCU; - /*FALLTHROUGH*/ + FALLTHROUGH /*FALLTHROUGH*/ case CTX_PROCESS_IMCU: /* Call postprocessor using previously set pointers */ (*cinfo->post->post_process_data) (cinfo, From 0081c2de20961f2b655c6c75c7bca6f52d5f8191 Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 7 Jul 2021 10:12:46 -0500 Subject: [PATCH 06/56] Neon/AArch32: Fix build if 'soft' float ABI used Arm compilers have three floating point ABI options: 'soft' compiles floating point operations as function calls into a software floating point library, which emulates floating point operations using integer operations. Floating point function arguments are passed using integer registers. 'softfp' also compiles floating point operations as function calls into a floating point library and passes floating point function arguments using integer registers, but the floating point library functions can use FPU instructions if the CPU supports them. 'hard' compiles floating point operations into inline FPU instructions, similarly to x86 and other architectures, and passes floating point function arguments using FPU registers. Not all AArch32 CPUs have FPUs or support Neon instructions, so on Linux and Android platforms, the AArch32 SIMD dispatcher in libjpeg-turbo only enables the Neon SIMD extensions at run time if /proc/cpuinfo indicates that the CPU supports Neon instructions or if Neon instructions are explicitly enabled (e.g. by passing -mfpu=neon to the compiler.) In order to support all AArch32 CPUs using the same code base, i.e. to support run-time FPU and Neon auto-detection, it is necessary to compile the scalar C source code using -mfloat-abi=soft. However, the 'soft' floating point ABI cannot be used when compiling Neon intrinsics, so the intrinsics implementation of the Neon SIMD extensions must be compiled using -mfloat-abi=softfp if the scalar C source code is compiled using -mfloat-abi=soft. This commit modifies the build system so that it detects whether -mfloat-abi=softfp must be explicitly added to the compiler flags when building the intrinsics implementation of the Neon SIMD extensions. This will be necessary if the build is using the 'soft' floating point ABI along with run-time auto-detection of Neon instructions. Fixes #523 --- ChangeLog.md | 4 ++++ cmakescripts/BuildPackages.cmake | 2 +- simd/CMakeLists.txt | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ea0f9031..096fcf06 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,10 @@ 1. Fixed a regression introduced in 2.1.0 that caused build failures with non-GCC-compatible compilers for Un*x/Arm platforms. +2. Fixed a regression introduced by 2.1 beta1[13] that prevented the Arm 32-bit +(AArch32) Neon SIMD extensions from building unless the C compiler flags +included `-mfloat-abi=softfp` or `-mfloat-abi=hard`. + 2.1.0 ===== diff --git a/cmakescripts/BuildPackages.cmake b/cmakescripts/BuildPackages.cmake index 3d35886f..37356a2c 100644 --- a/cmakescripts/BuildPackages.cmake +++ b/cmakescripts/BuildPackages.cmake @@ -27,7 +27,7 @@ elseif(CPU_TYPE STREQUAL "arm64") elseif(CPU_TYPE STREQUAL "arm") check_c_source_compiles(" #if __ARM_PCS_VFP != 1 - #error \"float ABI = softfp\" + #error \"float ABI != hard\" #endif int main(void) { return 0; }" HAVE_HARD_FLOAT) if(HAVE_HARD_FLOAT) diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index 7f380dce..e600b1e1 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -213,9 +213,37 @@ endif() elseif(CPU_TYPE STREQUAL "arm64" OR CPU_TYPE STREQUAL "arm") +# If Neon instructions are not explicitly enabled at compile time (e.g. using +# -mfpu=neon) with an AArch32 Linux or Android build, then the AArch32 SIMD +# dispatcher will parse /proc/cpuinfo to determine whether the Neon SIMD +# extensions can be enabled at run time. In order to support all AArch32 CPUs +# using the same code base, i.e. to support run-time FPU and Neon +# auto-detection, it is necessary to compile the scalar C source code using +# -mfloat-abi=soft (which is usually the default) but compile the intrinsics +# implementation of the Neon SIMD extensions using -mfloat-abi=softfp. The +# following test determines whether -mfloat-abi=softfp should be explicitly +# added to the compile flags for the intrinsics implementation of the Neon SIMD +# extensions. +if(BITS EQUAL 32) + check_c_source_compiles(" + #if defined(__ARM_NEON__) || (!defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__)) + #error \"Neon run-time auto-detection will not be used\" + #endif + #if __ARM_PCS_VFP == 1 + #error \"float ABI = hard\" + #endif + #if __SOFTFP__ != 1 + #error \"float ABI = softfp\" + #endif + int main(void) { return 0; }" NEED_SOFTFP_FOR_INTRINSICS) + if(NEED_SOFTFP_FOR_INTRINSICS) + set(SOFTFP_FLAG -mfloat-abi=softfp) + endif() +endif() + include(CheckSymbolExists) if(BITS EQUAL 32) - set(CMAKE_REQUIRED_FLAGS -mfpu=neon) + set(CMAKE_REQUIRED_FLAGS "-mfpu=neon ${SOFTFP_FLAG}") endif() check_symbol_exists(vld1_s16_x3 arm_neon.h HAVE_VLD1_S16_X3) check_symbol_exists(vld1_u16_x2 arm_neon.h HAVE_VLD1_U16_X2) @@ -263,7 +291,7 @@ if(NEON_INTRINSICS OR BITS EQUAL 32) arm/jdcolor-neon.c arm/jfdctint-neon.c) endif() if(BITS EQUAL 32) - set_source_files_properties(${SIMD_SOURCES} COMPILE_FLAGS -mfpu=neon) + set_source_files_properties(${SIMD_SOURCES} COMPILE_FLAGS "-mfpu=neon ${SOFTFP_FLAG}") endif() if(NOT NEON_INTRINSICS) enable_language(ASM) From 97a1575cb877e593cf9940cd869f41b1ddd4a4fd Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 7 Jul 2021 14:38:17 -0500 Subject: [PATCH 07/56] RPM: Don't include system lib dir in file list This resolves a conflict between the RPM generated by the libjpeg-turbo build system and the Red Hat 'filesystem' RPM if CMAKE_INSTALL_LIBDIR=/usr/lib[64]. This code was largely borrowed from the VirtualGL RPM spec. (I can legally do that because I hold the copyright on VirtualGL's implementation.) Fixes #532 --- release/rpm.spec.in | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/release/rpm.spec.in b/release/rpm.spec.in index 7274ea60..42070242 100644 --- a/release/rpm.spec.in +++ b/release/rpm.spec.in @@ -21,6 +21,12 @@ %endif %endif +%if "%{_bits}" == "64" +%define _syslibdir /usr/lib64 +%else +%define _syslibdir /usr/lib +%endif + #-->%if 1 %if "%{_bits}" == "64" %define _libdir %{_exec_prefix}/lib64 @@ -173,7 +179,9 @@ rm -rf $RPM_BUILD_ROOT %endif %{_bindir}/rdjpgcom %{_bindir}/wrjpgcom +%if "%{_libdir}" != "%{_syslibdir}" %dir %{_libdir} +%endif %if "%{_enable_shared}" == "1" %{_libdir}/libjpeg.so.@SO_MAJOR_VERSION@.@SO_AGE@.@SO_MINOR_VERSION@ %{_libdir}/libjpeg.so.@SO_MAJOR_VERSION@ From 2a2970af67a5602f1f25e048510f571061791168 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 9 Jul 2021 15:35:56 -0500 Subject: [PATCH 08/56] Neon/AArch32: Work around Clang T32 miscompilation Referring to the C standard (http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf, J.2 Undefined behavior), the behavior of the compiler is undefined if "conversion between two pointer types produces a result that is incorrectly aligned." Thus, the behavior of this code *((uint32_t *)buffer) = BUILTIN_BSWAP32(put_buffer); in the AArch32 version of the FLUSH() macro is undefined unless 'buffer' is 32-bit-aligned. Referring to https://bugs.llvm.org/show_bug.cgi?id=50785, certain versions of Clang, when generating Thumb (T32) instructions, miscompile that code into an assembly instruction (stm) that requires the destination to be 32-bit-aligned. Since such alignment cannot be guaranteed within the Huffman encoder, this reportedly led to crashes (SIGBUS: illegal alignment) with AArch32/Thumb builds of libjpeg-turbo running on Android devices, although thus far I have been unable to reproduce those crashes with a plain Linux/Arm system. The miscompilation is visible with the Compiler Explorer: https://godbolt.org/z/rv1ccx1Pb However, it goes away when removing the return statement from the function. Thus, it seems that Clang's behavior in this regard is somewhat variable, which may explain why the crashes are only reproducible on certain platforms. The suggested workaround is to use memcpy(), but whereas Clang and recent GCC releases are smart enough to compile a 4-byte memcpy() call into a str instruction, GCC < 6 is not. Referring to https://godbolt.org/z/ae7Wje3P6, the only way to consistently produce the desired str instruction across all supported compilers is to use inline assembly. Visual C++ presumably does not miscompile the code in question, since no issues have been reported with it, but since the code relies on undefined compiler behavior, prudence dictates that e4ec23d7ae051c1c73947f889818900362fdc52d should be reverted for Visual C++, which this commit does. The performance impact of e4ec23d7ae051c1c73947f889818900362fdc52d for Visual C++/Arm builds is unknown (I have no ability to test such builds), but regardless, this commit reverts the Visual C++/Arm performance to that of libjpeg-turbo 2.1 beta1. Closes #529 --- ChangeLog.md | 5 +++++ simd/arm/jchuff.h | 20 +++++++++++++++++--- simd/arm/neon-compat.h.in | 2 -- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 096fcf06..ca5208be 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,11 @@ non-GCC-compatible compilers for Un*x/Arm platforms. (AArch32) Neon SIMD extensions from building unless the C compiler flags included `-mfloat-abi=softfp` or `-mfloat-abi=hard`. +3. Fixed an issue in the AArch32 Neon SIMD Huffman encoder whereby reliance on +undefined C compiler behavior led to crashes ("SIGBUS: illegal alignment") on +Android systems when running AArch32/Thumb builds of libjpeg-turbo built with +recent versions of Clang. + 2.1.0 ===== diff --git a/simd/arm/jchuff.h b/simd/arm/jchuff.h index d4edd5eb..d0cbf9a0 100644 --- a/simd/arm/jchuff.h +++ b/simd/arm/jchuff.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2009, 2018, D. R. Commander. + * Copyright (C) 2009, 2018, 2021, D. R. Commander. * Copyright (C) 2018, Matthias Räncker. * Copyright (C) 2020-2021, Arm Limited. * For conditions of distribution and use, see the accompanying README.ijg @@ -74,6 +74,21 @@ typedef struct { #else +#if defined(_MSC_VER) && !defined(__clang__) +#define SPLAT() { \ + buffer[0] = (JOCTET)(put_buffer >> 24); \ + buffer[1] = (JOCTET)(put_buffer >> 16); \ + buffer[2] = (JOCTET)(put_buffer >> 8); \ + buffer[3] = (JOCTET)(put_buffer ); \ + buffer += 4; \ +} +#else +#define SPLAT() { \ + put_buffer = __builtin_bswap32(put_buffer); \ + __asm__("str %1, [%0], #4" : "=r" (buffer) : "r" (put_buffer)); \ +} +#endif + #define FLUSH() { \ if (put_buffer & 0x80808080 & ~(put_buffer + 0x01010101)) { \ EMIT_BYTE(put_buffer >> 24) \ @@ -81,8 +96,7 @@ typedef struct { EMIT_BYTE(put_buffer >> 8) \ EMIT_BYTE(put_buffer ) \ } else { \ - *((uint32_t *)buffer) = BUILTIN_BSWAP32(put_buffer); \ - buffer += 4; \ + SPLAT(); \ } \ } diff --git a/simd/arm/neon-compat.h.in b/simd/arm/neon-compat.h.in index 436c402a..d403f228 100644 --- a/simd/arm/neon-compat.h.in +++ b/simd/arm/neon-compat.h.in @@ -27,12 +27,10 @@ #if defined(_MSC_VER) && !defined(__clang__) #define BUILTIN_CLZ(x) _CountLeadingZeros(x) #define BUILTIN_CLZLL(x) _CountLeadingZeros64(x) -#define BUILTIN_BSWAP32(x) _byteswap_ulong(x) #define BUILTIN_BSWAP64(x) _byteswap_uint64(x) #elif defined(__clang__) || defined(__GNUC__) #define BUILTIN_CLZ(x) __builtin_clz(x) #define BUILTIN_CLZLL(x) __builtin_clzll(x) -#define BUILTIN_BSWAP32(x) __builtin_bswap32(x) #define BUILTIN_BSWAP64(x) __builtin_bswap64(x) #else #error "Unknown compiler" From a1bfc05854c416ce9c7f25f50cf01d533b19d49a Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 12 Jul 2021 13:52:38 -0500 Subject: [PATCH 09/56] Neon/AArch32: Mark inline asm output as read/write 'buffer' is both passed into the inline assembly code and modified by it. See https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html, 6.47.2.3. With GCC 4, this commit does not change the generated assembly code at all. With GCC 8, this commit fixes an assembly error: /tmp/{foo}.s: Assembler messages: /tmp/{foo}.s:775: Error: registers may not be the same -- `str r9,[r9],#4' I'm not sure why that error went unnoticed, since I definitely benchmarked the previous commit with GCC 8. Anyhow, this commit changes the generated assembly code slightly but does not alter performance. With Clang 10, this commit changes the generated assembly code slightly but does not alter performance. Refer to #529 --- simd/arm/jchuff.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simd/arm/jchuff.h b/simd/arm/jchuff.h index d0cbf9a0..2fbd252b 100644 --- a/simd/arm/jchuff.h +++ b/simd/arm/jchuff.h @@ -85,7 +85,7 @@ typedef struct { #else #define SPLAT() { \ put_buffer = __builtin_bswap32(put_buffer); \ - __asm__("str %1, [%0], #4" : "=r" (buffer) : "r" (put_buffer)); \ + __asm__("str %1, [%0], #4" : "+r" (buffer) : "r" (put_buffer)); \ } #endif From b201838d8b5f2f80c9f86ec8405a62a002232b2c Mon Sep 17 00:00:00 2001 From: Peter Kasting Date: Sat, 10 Jul 2021 16:07:05 -0700 Subject: [PATCH 10/56] Neon: Silence -Wimplicit-fallthrough warnings Refer to https://bugs.chromium.org/p/chromium/issues/detail?id=995993 Closes #534 --- simd/arm/jcphuff-neon.c | 31 ++++++++++++++++++++++ simd/arm/jdcolext-neon.c | 21 +++++++++++++++ simd/arm/jdcolor-neon.c | 1 + simd/arm/jdmerge-neon.c | 1 + simd/arm/jdmrgext-neon.c | 56 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 110 insertions(+) diff --git a/simd/arm/jcphuff-neon.c b/simd/arm/jcphuff-neon.c index 86a263fa..b91c5db4 100644 --- a/simd/arm/jcphuff-neon.c +++ b/simd/arm/jcphuff-neon.c @@ -21,6 +21,7 @@ */ #define JPEG_INTERNALS +#include "jconfigint.h" #include "../../jinclude.h" #include "../../jpeglib.h" #include "../../jsimd.h" @@ -105,18 +106,25 @@ void jsimd_encode_mcu_AC_first_prepare_neon switch (remaining_coefs) { case 15: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[14], coefs2, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[13], coefs2, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[12], coefs2, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[11], coefs2, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[10], coefs2, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[9], coefs2, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[8], coefs2, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -149,20 +157,28 @@ void jsimd_encode_mcu_AC_first_prepare_neon switch (remaining_coefs) { case 8: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[7], coefs, 7); + FALLTHROUGH /*FALLTHROUGH*/ case 7: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[6], coefs, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[5], coefs, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[4], coefs, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[3], coefs, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[2], coefs, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[1], coefs, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[0], coefs, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -337,18 +353,25 @@ int jsimd_encode_mcu_AC_refine_prepare_neon switch (remaining_coefs) { case 15: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[14], coefs2, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[13], coefs2, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[12], coefs2, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[11], coefs2, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[10], coefs2, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[9], coefs2, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[8], coefs2, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -389,20 +412,28 @@ int jsimd_encode_mcu_AC_refine_prepare_neon switch (remaining_coefs) { case 8: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[7], coefs, 7); + FALLTHROUGH /*FALLTHROUGH*/ case 7: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[6], coefs, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[5], coefs, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[4], coefs, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[3], coefs, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[2], coefs, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[1], coefs, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: coefs = vld1q_lane_s16(block + jpeg_natural_order_start[0], coefs, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } diff --git a/simd/arm/jdcolext-neon.c b/simd/arm/jdcolext-neon.c index ae440f45..c3c07a19 100644 --- a/simd/arm/jdcolext-neon.c +++ b/simd/arm/jdcolext-neon.c @@ -283,18 +283,25 @@ void jsimd_ycc_rgb_convert_neon(JDIMENSION output_width, JSAMPIMAGE input_buf, switch (cols_remaining) { case 7: vst4_lane_u8(outptr + 6 * RGB_PIXELSIZE, rgba, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst4_lane_u8(outptr + 5 * RGB_PIXELSIZE, rgba, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst4_lane_u8(outptr + 4 * RGB_PIXELSIZE, rgba, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst4_lane_u8(outptr + 3 * RGB_PIXELSIZE, rgba, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst4_lane_u8(outptr + 2 * RGB_PIXELSIZE, rgba, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst4_lane_u8(outptr + RGB_PIXELSIZE, rgba, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst4_lane_u8(outptr, rgba, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -308,18 +315,25 @@ void jsimd_ycc_rgb_convert_neon(JDIMENSION output_width, JSAMPIMAGE input_buf, switch (cols_remaining) { case 7: vst3_lane_u8(outptr + 6 * RGB_PIXELSIZE, rgb, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst3_lane_u8(outptr + 5 * RGB_PIXELSIZE, rgb, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst3_lane_u8(outptr + 4 * RGB_PIXELSIZE, rgb, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst3_lane_u8(outptr + 3 * RGB_PIXELSIZE, rgb, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst3_lane_u8(outptr + 2 * RGB_PIXELSIZE, rgb, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst3_lane_u8(outptr + RGB_PIXELSIZE, rgb, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst3_lane_u8(outptr, rgb, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -332,18 +346,25 @@ void jsimd_ycc_rgb_convert_neon(JDIMENSION output_width, JSAMPIMAGE input_buf, switch (cols_remaining) { case 7: vst1q_lane_u16((uint16_t *)(outptr + 6 * RGB_PIXELSIZE), rgb565, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst1q_lane_u16((uint16_t *)(outptr + 5 * RGB_PIXELSIZE), rgb565, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst1q_lane_u16((uint16_t *)(outptr + 4 * RGB_PIXELSIZE), rgb565, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst1q_lane_u16((uint16_t *)(outptr + 3 * RGB_PIXELSIZE), rgb565, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst1q_lane_u16((uint16_t *)(outptr + 2 * RGB_PIXELSIZE), rgb565, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst1q_lane_u16((uint16_t *)(outptr + RGB_PIXELSIZE), rgb565, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst1q_lane_u16((uint16_t *)outptr, rgb565, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } diff --git a/simd/arm/jdcolor-neon.c b/simd/arm/jdcolor-neon.c index 28dbc572..ea4668f1 100644 --- a/simd/arm/jdcolor-neon.c +++ b/simd/arm/jdcolor-neon.c @@ -21,6 +21,7 @@ */ #define JPEG_INTERNALS +#include "jconfigint.h" #include "../../jinclude.h" #include "../../jpeglib.h" #include "../../jsimd.h" diff --git a/simd/arm/jdmerge-neon.c b/simd/arm/jdmerge-neon.c index 18fb9d8a..e4f91fdc 100644 --- a/simd/arm/jdmerge-neon.c +++ b/simd/arm/jdmerge-neon.c @@ -21,6 +21,7 @@ */ #define JPEG_INTERNALS +#include "jconfigint.h" #include "../../jinclude.h" #include "../../jpeglib.h" #include "../../jsimd.h" diff --git a/simd/arm/jdmrgext-neon.c b/simd/arm/jdmrgext-neon.c index fa2ec056..5b89bdb3 100644 --- a/simd/arm/jdmrgext-neon.c +++ b/simd/arm/jdmrgext-neon.c @@ -226,35 +226,49 @@ void jsimd_h2v1_merged_upsample_neon(JDIMENSION output_width, switch (cols_remaining) { case 15: vst4_lane_u8(outptr + 14 * RGB_PIXELSIZE, rgba_h, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: vst4_lane_u8(outptr + 13 * RGB_PIXELSIZE, rgba_h, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: vst4_lane_u8(outptr + 12 * RGB_PIXELSIZE, rgba_h, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: vst4_lane_u8(outptr + 11 * RGB_PIXELSIZE, rgba_h, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: vst4_lane_u8(outptr + 10 * RGB_PIXELSIZE, rgba_h, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: vst4_lane_u8(outptr + 9 * RGB_PIXELSIZE, rgba_h, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: vst4_lane_u8(outptr + 8 * RGB_PIXELSIZE, rgba_h, 0); + FALLTHROUGH /*FALLTHROUGH*/ case 8: vst4_u8(outptr, rgba_l); break; case 7: vst4_lane_u8(outptr + 6 * RGB_PIXELSIZE, rgba_l, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst4_lane_u8(outptr + 5 * RGB_PIXELSIZE, rgba_l, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst4_lane_u8(outptr + 4 * RGB_PIXELSIZE, rgba_l, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst4_lane_u8(outptr + 3 * RGB_PIXELSIZE, rgba_l, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst4_lane_u8(outptr + 2 * RGB_PIXELSIZE, rgba_l, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst4_lane_u8(outptr + RGB_PIXELSIZE, rgba_l, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst4_lane_u8(outptr, rgba_l, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -271,35 +285,49 @@ void jsimd_h2v1_merged_upsample_neon(JDIMENSION output_width, switch (cols_remaining) { case 15: vst3_lane_u8(outptr + 14 * RGB_PIXELSIZE, rgb_h, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: vst3_lane_u8(outptr + 13 * RGB_PIXELSIZE, rgb_h, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: vst3_lane_u8(outptr + 12 * RGB_PIXELSIZE, rgb_h, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: vst3_lane_u8(outptr + 11 * RGB_PIXELSIZE, rgb_h, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: vst3_lane_u8(outptr + 10 * RGB_PIXELSIZE, rgb_h, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: vst3_lane_u8(outptr + 9 * RGB_PIXELSIZE, rgb_h, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: vst3_lane_u8(outptr + 8 * RGB_PIXELSIZE, rgb_h, 0); + FALLTHROUGH /*FALLTHROUGH*/ case 8: vst3_u8(outptr, rgb_l); break; case 7: vst3_lane_u8(outptr + 6 * RGB_PIXELSIZE, rgb_l, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst3_lane_u8(outptr + 5 * RGB_PIXELSIZE, rgb_l, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst3_lane_u8(outptr + 4 * RGB_PIXELSIZE, rgb_l, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst3_lane_u8(outptr + 3 * RGB_PIXELSIZE, rgb_l, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst3_lane_u8(outptr + 2 * RGB_PIXELSIZE, rgb_l, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst3_lane_u8(outptr + RGB_PIXELSIZE, rgb_l, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst3_lane_u8(outptr, rgb_l, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -549,24 +577,31 @@ void jsimd_h2v2_merged_upsample_neon(JDIMENSION output_width, case 15: vst4_lane_u8(outptr0 + 14 * RGB_PIXELSIZE, rgba0_h, 6); vst4_lane_u8(outptr1 + 14 * RGB_PIXELSIZE, rgba1_h, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: vst4_lane_u8(outptr0 + 13 * RGB_PIXELSIZE, rgba0_h, 5); vst4_lane_u8(outptr1 + 13 * RGB_PIXELSIZE, rgba1_h, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: vst4_lane_u8(outptr0 + 12 * RGB_PIXELSIZE, rgba0_h, 4); vst4_lane_u8(outptr1 + 12 * RGB_PIXELSIZE, rgba1_h, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: vst4_lane_u8(outptr0 + 11 * RGB_PIXELSIZE, rgba0_h, 3); vst4_lane_u8(outptr1 + 11 * RGB_PIXELSIZE, rgba1_h, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: vst4_lane_u8(outptr0 + 10 * RGB_PIXELSIZE, rgba0_h, 2); vst4_lane_u8(outptr1 + 10 * RGB_PIXELSIZE, rgba1_h, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: vst4_lane_u8(outptr0 + 9 * RGB_PIXELSIZE, rgba0_h, 1); vst4_lane_u8(outptr1 + 9 * RGB_PIXELSIZE, rgba1_h, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: vst4_lane_u8(outptr0 + 8 * RGB_PIXELSIZE, rgba0_h, 0); vst4_lane_u8(outptr1 + 8 * RGB_PIXELSIZE, rgba1_h, 0); + FALLTHROUGH /*FALLTHROUGH*/ case 8: vst4_u8(outptr0, rgba0_l); vst4_u8(outptr1, rgba1_l); @@ -574,24 +609,31 @@ void jsimd_h2v2_merged_upsample_neon(JDIMENSION output_width, case 7: vst4_lane_u8(outptr0 + 6 * RGB_PIXELSIZE, rgba0_l, 6); vst4_lane_u8(outptr1 + 6 * RGB_PIXELSIZE, rgba1_l, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst4_lane_u8(outptr0 + 5 * RGB_PIXELSIZE, rgba0_l, 5); vst4_lane_u8(outptr1 + 5 * RGB_PIXELSIZE, rgba1_l, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst4_lane_u8(outptr0 + 4 * RGB_PIXELSIZE, rgba0_l, 4); vst4_lane_u8(outptr1 + 4 * RGB_PIXELSIZE, rgba1_l, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst4_lane_u8(outptr0 + 3 * RGB_PIXELSIZE, rgba0_l, 3); vst4_lane_u8(outptr1 + 3 * RGB_PIXELSIZE, rgba1_l, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst4_lane_u8(outptr0 + 2 * RGB_PIXELSIZE, rgba0_l, 2); vst4_lane_u8(outptr1 + 2 * RGB_PIXELSIZE, rgba1_l, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst4_lane_u8(outptr0 + 1 * RGB_PIXELSIZE, rgba0_l, 1); vst4_lane_u8(outptr1 + 1 * RGB_PIXELSIZE, rgba1_l, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst4_lane_u8(outptr0, rgba0_l, 0); vst4_lane_u8(outptr1, rgba1_l, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } @@ -616,24 +658,31 @@ void jsimd_h2v2_merged_upsample_neon(JDIMENSION output_width, case 15: vst3_lane_u8(outptr0 + 14 * RGB_PIXELSIZE, rgb0_h, 6); vst3_lane_u8(outptr1 + 14 * RGB_PIXELSIZE, rgb1_h, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 14: vst3_lane_u8(outptr0 + 13 * RGB_PIXELSIZE, rgb0_h, 5); vst3_lane_u8(outptr1 + 13 * RGB_PIXELSIZE, rgb1_h, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 13: vst3_lane_u8(outptr0 + 12 * RGB_PIXELSIZE, rgb0_h, 4); vst3_lane_u8(outptr1 + 12 * RGB_PIXELSIZE, rgb1_h, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 12: vst3_lane_u8(outptr0 + 11 * RGB_PIXELSIZE, rgb0_h, 3); vst3_lane_u8(outptr1 + 11 * RGB_PIXELSIZE, rgb1_h, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 11: vst3_lane_u8(outptr0 + 10 * RGB_PIXELSIZE, rgb0_h, 2); vst3_lane_u8(outptr1 + 10 * RGB_PIXELSIZE, rgb1_h, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 10: vst3_lane_u8(outptr0 + 9 * RGB_PIXELSIZE, rgb0_h, 1); vst3_lane_u8(outptr1 + 9 * RGB_PIXELSIZE, rgb1_h, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 9: vst3_lane_u8(outptr0 + 8 * RGB_PIXELSIZE, rgb0_h, 0); vst3_lane_u8(outptr1 + 8 * RGB_PIXELSIZE, rgb1_h, 0); + FALLTHROUGH /*FALLTHROUGH*/ case 8: vst3_u8(outptr0, rgb0_l); vst3_u8(outptr1, rgb1_l); @@ -641,24 +690,31 @@ void jsimd_h2v2_merged_upsample_neon(JDIMENSION output_width, case 7: vst3_lane_u8(outptr0 + 6 * RGB_PIXELSIZE, rgb0_l, 6); vst3_lane_u8(outptr1 + 6 * RGB_PIXELSIZE, rgb1_l, 6); + FALLTHROUGH /*FALLTHROUGH*/ case 6: vst3_lane_u8(outptr0 + 5 * RGB_PIXELSIZE, rgb0_l, 5); vst3_lane_u8(outptr1 + 5 * RGB_PIXELSIZE, rgb1_l, 5); + FALLTHROUGH /*FALLTHROUGH*/ case 5: vst3_lane_u8(outptr0 + 4 * RGB_PIXELSIZE, rgb0_l, 4); vst3_lane_u8(outptr1 + 4 * RGB_PIXELSIZE, rgb1_l, 4); + FALLTHROUGH /*FALLTHROUGH*/ case 4: vst3_lane_u8(outptr0 + 3 * RGB_PIXELSIZE, rgb0_l, 3); vst3_lane_u8(outptr1 + 3 * RGB_PIXELSIZE, rgb1_l, 3); + FALLTHROUGH /*FALLTHROUGH*/ case 3: vst3_lane_u8(outptr0 + 2 * RGB_PIXELSIZE, rgb0_l, 2); vst3_lane_u8(outptr1 + 2 * RGB_PIXELSIZE, rgb1_l, 2); + FALLTHROUGH /*FALLTHROUGH*/ case 2: vst3_lane_u8(outptr0 + 1 * RGB_PIXELSIZE, rgb0_l, 1); vst3_lane_u8(outptr1 + 1 * RGB_PIXELSIZE, rgb1_l, 1); + FALLTHROUGH /*FALLTHROUGH*/ case 1: vst3_lane_u8(outptr0, rgb0_l, 0); vst3_lane_u8(outptr1, rgb1_l, 0); + FALLTHROUGH /*FALLTHROUGH*/ default: break; } From 4d9f256b0184bf8ee6e59e8cdf34c7d577d81b27 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 13 Jul 2021 11:52:49 -0500 Subject: [PATCH 11/56] jpegtran: Add option to copy only ICC markers Closes #533 --- ChangeLog.md | 4 ++++ jpegtran.1 | 8 ++++++-- jpegtran.c | 7 ++++++- transupp.c | 8 ++++++-- transupp.h | 11 ++++++----- usage.txt | 3 +++ 6 files changed, 31 insertions(+), 10 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ca5208be..22bfa007 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -15,6 +15,10 @@ undefined C compiler behavior led to crashes ("SIGBUS: illegal alignment") on Android systems when running AArch32/Thumb builds of libjpeg-turbo built with recent versions of Clang. +4. Added a command-line argument (`-copy icc`) to jpegtran that causes it to +copy only the ICC profile markers from the source file and discard any other +metadata. + 2.1.0 ===== diff --git a/jpegtran.1 b/jpegtran.1 index da7a2669..5b1ded24 100644 --- a/jpegtran.1 +++ b/jpegtran.1 @@ -1,4 +1,4 @@ -.TH JPEGTRAN 1 "26 October 2020" +.TH JPEGTRAN 1 "13 July 2021" .SH NAME jpegtran \- lossless transformation of JPEG files .SH SYNOPSIS @@ -247,6 +247,10 @@ comments and other metadata in the source file. Copy only comment markers. This setting copies comments from the source file but discards any other metadata. .TP +.B \-copy icc +Copy only ICC profile markers. This setting copies the ICC profile from the +source file but discards any other metadata. +.TP .B \-copy all Copy all extra markers. This setting preserves miscellaneous markers found in the source file, such as JFIF thumbnails, Exif data, and Photoshop @@ -261,7 +265,7 @@ Additional switches recognized by jpegtran are: .BI \-icc " file" Embed ICC color management profile contained in the specified file. Note that this will cause \fBjpegtran\fR to ignore any APP2 markers in the input file, -even if \fB-copy all\fR is specified. +even if \fB-copy all\fR or \fB-copy icc\fR is specified. .TP .BI \-maxmemory " N" Set limit for amount of memory to use in processing large images. Value is diff --git a/jpegtran.c b/jpegtran.c index 244996dd..7dd27232 100644 --- a/jpegtran.c +++ b/jpegtran.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2014, 2017, 2019-2020, D. R. Commander. + * Copyright (C) 2010, 2014, 2017, 2019-2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -64,6 +64,7 @@ usage(void) fprintf(stderr, "Switches (names may be abbreviated):\n"); fprintf(stderr, " -copy none Copy no extra markers from source file\n"); fprintf(stderr, " -copy comments Copy only comment markers (default)\n"); + fprintf(stderr, " -copy icc Copy only ICC profile markers\n"); fprintf(stderr, " -copy all Copy all extra markers\n"); #ifdef ENTROPY_OPT_SUPPORTED fprintf(stderr, " -optimize Optimize Huffman table (smaller file, but slow compression)\n"); @@ -196,6 +197,8 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv, copyoption = JCOPYOPT_NONE; } else if (keymatch(argv[argn], "comments", 1)) { copyoption = JCOPYOPT_COMMENTS; + } else if (keymatch(argv[argn], "icc", 1)) { + copyoption = JCOPYOPT_ICC; } else if (keymatch(argv[argn], "all", 1)) { copyoption = JCOPYOPT_ALL; } else @@ -570,6 +573,8 @@ main(int argc, char **argv) fclose(icc_file); if (copyoption == JCOPYOPT_ALL) copyoption = JCOPYOPT_ALL_EXCEPT_ICC; + if (copyoption == JCOPYOPT_ICC) + copyoption = JCOPYOPT_NONE; } if (report) { diff --git a/transupp.c b/transupp.c index 6e860778..ce30ab7b 100644 --- a/transupp.c +++ b/transupp.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2017, D. R. Commander. + * Copyright (C) 2010, 2017, 2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -2310,7 +2310,7 @@ jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option) int m; /* Save comments except under NONE option */ - if (option != JCOPYOPT_NONE) { + if (option != JCOPYOPT_NONE && option != JCOPYOPT_ICC) { jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); } /* Save all types of APPn markers iff ALL option */ @@ -2321,6 +2321,10 @@ jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option) jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); } } + /* Save only APP2 markers if ICC option selected */ + if (option == JCOPYOPT_ICC) { + jpeg_save_markers(srcinfo, JPEG_APP0 + 2, 0xFFFF); + } #endif /* SAVE_MARKERS_SUPPORTED */ } diff --git a/transupp.h b/transupp.h index ea6be1fc..cea1f409 100644 --- a/transupp.h +++ b/transupp.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2017, D. R. Commander. + * Copyright (C) 2017, 2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -213,10 +213,11 @@ EXTERN(boolean) jtransform_perfect_transform(JDIMENSION image_width, */ typedef enum { - JCOPYOPT_NONE, /* copy no optional markers */ - JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ - JCOPYOPT_ALL, /* copy all optional markers */ - JCOPYOPT_ALL_EXCEPT_ICC /* copy all optional markers except APP2 */ + JCOPYOPT_NONE, /* copy no optional markers */ + JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ + JCOPYOPT_ALL, /* copy all optional markers */ + JCOPYOPT_ALL_EXCEPT_ICC, /* copy all optional markers except APP2 */ + JCOPYOPT_ICC /* copy only ICC profile (APP2) markers */ } JCOPY_OPTION; #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ diff --git a/usage.txt b/usage.txt index f7fa3c08..b60a593f 100644 --- a/usage.txt +++ b/usage.txt @@ -601,6 +601,9 @@ markers, such as comment blocks: -copy comments Copy only comment markers. This setting copies comments from the source file but discards any other metadata. + -copy icc Copy only ICC profile markers. This setting copies the + ICC profile from the source file but discards any other + metadata. -copy all Copy all extra markers. This setting preserves miscellaneous markers found in the source file, such as JFIF thumbnails, Exif data, and Photoshop settings. From a72816ed07d71e34de07324ede020780d73c5c21 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Fri, 16 Jul 2021 09:37:06 +0100 Subject: [PATCH 12/56] Use uintptr_t, if avail, for pointer-to-int casts Although sizeof(void *) == sizeof(size_t) for all architectures that are currently supported by libjpeg-turbo, such is not guaranteed by the C standard. Specifically, CHERI-enabled architectures (e.g. CHERI-RISC-V or Arm's Morello) use capability pointers that are twice the size of size_t (128 bits for Morello and RV64), so casting to size_t strips the upper bits of the pointer (including the validity bit) and makes it non-deferenceable, as indicated by the following compiler warning: warning: cast from provenance-free integer type to pointer type will give pointer that can not be dereferenced [-Werror,-Wcheri-capability-misuse] cvalue = values = (JCOEF *)PAD((size_t)values_unaligned, 16); Ignoring this warning results in a run-time crash. Casting pointers to uintptr_t, if it is available, avoids this problem, since uintptr_t is defined as an unsigned integer type that can hold a pointer value. Since C89 compatibility is still necessary in libjpeg-turbo, this commit introduces a new typedef for pointer-to-integer casts that uses a GNU-specific extension available in GCC 4.6+ and Clang 3.0+ and falls back to using size_t if the extension is unavailable. The only other options would require C99 or Clang-specific builtins. Closes #538 --- ChangeLog.md | 3 +++ jcphuff.c | 5 +++-- jpegint.h | 15 ++++++++++++++- turbojpeg.c | 7 ++++--- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 22bfa007..186bd02b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -19,6 +19,9 @@ recent versions of Clang. copy only the ICC profile markers from the source file and discard any other metadata. +5. libjpeg-turbo should now build and run on CHERI-enabled architectures, which +use capability pointers that are larger than the size of `size_t`. + 2.1.0 ===== diff --git a/jcphuff.c b/jcphuff.c index 9bf96124..11019871 100644 --- a/jcphuff.c +++ b/jcphuff.c @@ -7,6 +7,7 @@ * Copyright (C) 2011, 2015, 2018, 2021, D. R. Commander. * Copyright (C) 2016, 2018, Matthieu Darbois. * Copyright (C) 2020, Arm Limited. + * Copyright (C) 2021, Alex Richardson. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -680,7 +681,7 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data) emit_restart(entropy, entropy->next_restart_num); #ifdef WITH_SIMD - cvalue = values = (JCOEF *)PAD((size_t)values_unaligned, 16); + cvalue = values = (JCOEF *)PAD((JUINTPTR)values_unaligned, 16); #else /* Not using SIMD, so alignment is not needed */ cvalue = values = values_unaligned; @@ -945,7 +946,7 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data) emit_restart(entropy, entropy->next_restart_num); #ifdef WITH_SIMD - cabsvalue = absvalues = (JCOEF *)PAD((size_t)absvalues_unaligned, 16); + cabsvalue = absvalues = (JCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16); #else /* Not using SIMD, so alignment is not needed */ cabsvalue = absvalues = absvalues_unaligned; diff --git a/jpegint.h b/jpegint.h index 195fbcb9..8c853479 100644 --- a/jpegint.h +++ b/jpegint.h @@ -5,8 +5,9 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015-2016, 2019, D. R. Commander. + * Copyright (C) 2015-2016, 2019, 2021, D. R. Commander. * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2021, Alex Richardson. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -47,6 +48,18 @@ typedef enum { /* Operating modes for buffer controllers */ /* JLONG must hold at least signed 32-bit values. */ typedef long JLONG; +/* JUINTPTR must hold pointer values. */ +#ifdef __UINTPTR_TYPE__ +/* + * __UINTPTR_TYPE__ is GNU-specific and available in GCC 4.6+ and Clang 3.0+. + * Fortunately, that is sufficient to support the few architectures for which + * sizeof(void *) != sizeof(size_t). The only other options would require C99 + * or Clang-specific builtins. + */ +typedef __UINTPTR_TYPE__ JUINTPTR; +#else +typedef size_t JUINTPTR; +#endif /* * Left shift macro that handles a negative operand without causing any diff --git a/turbojpeg.c b/turbojpeg.c index 793a3eed..47c59993 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -1,5 +1,6 @@ /* * Copyright (C)2009-2021 D. R. Commander. All Rights Reserved. + * Copyright (C)2021 Alex Richardson. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -845,7 +846,7 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf, THROW("tjEncodeYUVPlanes(): Memory allocation failure"); for (row = 0; row < cinfo->max_v_samp_factor; row++) { unsigned char *_tmpbuf_aligned = - (unsigned char *)PAD((size_t)_tmpbuf[i], 32); + (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32); tmpbuf[i][row] = &_tmpbuf_aligned[ PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) / @@ -861,7 +862,7 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf, THROW("tjEncodeYUVPlanes(): Memory allocation failure"); for (row = 0; row < compptr->v_samp_factor; row++) { unsigned char *_tmpbuf2_aligned = - (unsigned char *)PAD((size_t)_tmpbuf2[i], 32); + (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32); tmpbuf2[i][row] = &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; @@ -1524,7 +1525,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle, THROW("tjDecodeYUVPlanes(): Memory allocation failure"); for (row = 0; row < compptr->v_samp_factor; row++) { unsigned char *_tmpbuf_aligned = - (unsigned char *)PAD((size_t)_tmpbuf[i], 32); + (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32); tmpbuf[i][row] = &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; From e6e952d5d5db6c0f9c505854995988ad13b30ec8 Mon Sep 17 00:00:00 2001 From: y-guyon <51164219+y-guyon@users.noreply.github.com> Date: Thu, 15 Jul 2021 17:33:24 +0200 Subject: [PATCH 13/56] Suppress UBSan error in decode_mcu_fast() This is the same error that d147be83e9a9f904918ba7f834b0fb28e09de9b5 suppressed in decode_mcu_slow(). The image that reproduces this error in decode_mcu_fast() has been added to the libjpeg-turbo seed corpora. Closes #537 --- jdhuff.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/jdhuff.c b/jdhuff.c index f786c105..679d2216 100644 --- a/jdhuff.c +++ b/jdhuff.c @@ -584,7 +584,7 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) * behavior is, to the best of our understanding, innocuous, and it is * unclear how to work around it without potentially affecting * performance. Thus, we (hopefully temporarily) suppress UBSan integer - * overflow errors for this function. + * overflow errors for this function and decode_mcu_fast(). */ s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; @@ -651,6 +651,12 @@ decode_mcu_slow(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) } +#if defined(__has_feature) +#if __has_feature(undefined_behavior_sanitizer) +__attribute__((no_sanitize("signed-integer-overflow"), + no_sanitize("unsigned-integer-overflow"))) +#endif +#endif LOCAL(boolean) decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) { @@ -681,6 +687,9 @@ decode_mcu_fast(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) if (entropy->dc_needed[blkn]) { int ci = cinfo->MCU_membership[blkn]; + /* Refer to the comment in decode_mcu_slow() regarding the supression of + * a UBSan integer overflow error in this line of code. + */ s += state.last_dc_val[ci]; state.last_dc_val[ci] = s; if (block) From 84d6306f64afd189de148ff13895537a24a55dd3 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 27 Jul 2021 11:02:23 -0500 Subject: [PATCH 14/56] Fix build w/CMake 3.14+ when CMAKE_SYSTEM_NAME=iOS Closes #539 --- CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53e59c41..c01ec250 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,15 @@ pad_number(VERSION_MINOR 3) pad_number(VERSION_REVISION 3) set(LIBJPEG_TURBO_VERSION_NUMBER ${VERSION_MAJOR}${VERSION_MINOR}${VERSION_REVISION}) +# CMake 3.14 and later sets CMAKE_MACOSX_BUNDLE to TRUE by default when +# CMAKE_SYSTEM_NAME is iOS, tvOS, or watchOS, which breaks the libjpeg-turbo +# build. (Specifically, when CMAKE_MACOSX_BUNDLE is TRUE, executables for +# Apple platforms are built as application bundles, which causes CMake to +# complain that our install() directives for executables do not specify a +# BUNDLE DESTINATION. Even if CMake did not complain, building executables as +# application bundles would break our iOS packages.) +set(CMAKE_MACOSX_BUNDLE FALSE) + string(TIMESTAMP DEFAULT_BUILD "%Y%m%d") set(BUILD ${DEFAULT_BUILD} CACHE STRING "Build string (default: ${DEFAULT_BUILD})") From 2849d86aaae168fcac2e1b6c373c249781a41c5c Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 6 Aug 2021 13:41:15 -0500 Subject: [PATCH 15/56] SSE2/64-bit: Fix trans. segfault w/ malformed JPEG Attempting to losslessly transform certain malformed JPEG images can cause the nbits table index in the Huffman encoder to exceed 32768, so we need to pad the SSE2 implementation of that table to 65536 entries as we do with the C implementation. Regression introduced by 087c29e07f7533ec82fd7eb1dafc84c29e7870ec Fixes #543 --- ChangeLog.md | 4 ++++ simd/x86_64/jchuff-sse2.asm | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 186bd02b..1fcb065a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,6 +22,10 @@ metadata. 5. libjpeg-turbo should now build and run on CHERI-enabled architectures, which use capability pointers that are larger than the size of `size_t`. +6. Fixed a regression introduced by 2.1 beta1[5] that caused a segfault in the +64-bit SSE2 Huffman encoder when attempting to losslessly transform a +specially-crafted malformed JPEG image. + 2.1.0 ===== diff --git a/simd/x86_64/jchuff-sse2.asm b/simd/x86_64/jchuff-sse2.asm index 00720283..9ea6df94 100644 --- a/simd/x86_64/jchuff-sse2.asm +++ b/simd/x86_64/jchuff-sse2.asm @@ -1,7 +1,7 @@ ; ; jchuff-sse2.asm - Huffman entropy encoding (64-bit SSE2) ; -; Copyright (C) 2009-2011, 2014-2016, 2019, D. R. Commander. +; Copyright (C) 2009-2011, 2014-2016, 2019, 2021, D. R. Commander. ; Copyright (C) 2015, Matthieu Darbois. ; Copyright (C) 2018, Matthias Räncker. ; @@ -83,6 +83,7 @@ times 1 << 11 db 12 times 1 << 12 db 13 times 1 << 13 db 14 times 1 << 14 db 15 +times 1 << 15 db 16 alignz 32 From 0a9b9721782d3a60a5c16c8c9a7abf3d4b1ecd42 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 9 Aug 2021 17:25:36 -0500 Subject: [PATCH 16/56] jmemmgr.c: Pass correct size arg to jpeg_free_*() This issue was introduced in 5557fd22173ea9ab4c02c81e1dcec9bd6927814f due to an oversight, so it has existed in libjpeg-turbo since the project's inception. However, the issue is effectively a non-issue. Although #325 proposes allowing programs to override jpeg_get_*() and jpeg_free_*() externally, there is currently no way to override those functions without modifying the libjpeg-turbo source code. libjpeg-turbo only includes the malloc()/free() memory manager from libjpeg, and the implementation of jpeg_free_*() in that memory manager ignores the size argument. libjpeg had several additional memory managers for legacy systems (MS-DOS, System 7, etc.), but those memory managers ignored the size argument to jpeg_free_*() as well. Thus, this issue would have only potentially affected custom memory managers in downstream libjpeg-turbo forks, and since no one has complained until now, apparently those are rare. Fixes #542 --- jmemmgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jmemmgr.c b/jmemmgr.c index 508ca742..70b8ec0c 100644 --- a/jmemmgr.c +++ b/jmemmgr.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2016, D. R. Commander. + * Copyright (C) 2016, 2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -1032,7 +1032,7 @@ free_pool(j_common_ptr cinfo, int pool_id) large_pool_ptr next_lhdr_ptr = lhdr_ptr->next; space_freed = lhdr_ptr->bytes_used + lhdr_ptr->bytes_left + - sizeof(large_pool_hdr); + sizeof(large_pool_hdr) + ALIGN_SIZE - 1; jpeg_free_large(cinfo, (void *)lhdr_ptr, space_freed); mem->total_space_allocated -= space_freed; lhdr_ptr = next_lhdr_ptr; @@ -1045,7 +1045,7 @@ free_pool(j_common_ptr cinfo, int pool_id) while (shdr_ptr != NULL) { small_pool_ptr next_shdr_ptr = shdr_ptr->next; space_freed = shdr_ptr->bytes_used + shdr_ptr->bytes_left + - sizeof(small_pool_hdr); + sizeof(small_pool_hdr) + ALIGN_SIZE - 1; jpeg_free_small(cinfo, (void *)shdr_ptr, space_freed); mem->total_space_allocated -= space_freed; shdr_ptr = next_shdr_ptr; From 129f0cb76346ceede8f4d8d87dea8acb0809056c Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 25 Aug 2021 12:07:58 -0500 Subject: [PATCH 17/56] Neon/AArch64: Don't put GAS functions in .rodata Regression introduced by 240ba417aa4b3174850d05ea0d22dbe5f80553c1 Closes #546 --- CMakeLists.txt | 2 +- ChangeLog.md | 12 ++++++++++++ simd/arm/aarch64/jsimd_neon.S | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c01ec250..4e5dd367 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if(CMAKE_EXECUTABLE_SUFFIX) endif() project(libjpeg-turbo C) -set(VERSION 2.1.1) +set(VERSION 2.1.2) 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 1fcb065a..bcbb0079 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,15 @@ +2.1.2 +===== + +1. Fixed a regression introduced by 2.1 beta1[13] that caused the remaining +GAS implementations of AArch64 (Arm 64-bit) Neon SIMD functions (which are used +by default with GCC for performance reasons) to be placed in the `.rodata` +section rather than in the `.text` section. This caused the GNU linker to +automatically place the `.rodata` section in an executable segment, which +prevented libjpeg-turbo from working properly with other linkers and also +represented a potential security risk. + + 2.1.1 ===== diff --git a/simd/arm/aarch64/jsimd_neon.S b/simd/arm/aarch64/jsimd_neon.S index 31aa8e25..738a4f06 100644 --- a/simd/arm/aarch64/jsimd_neon.S +++ b/simd/arm/aarch64/jsimd_neon.S @@ -182,6 +182,8 @@ Ljsimd_huff_encode_one_block_neon_consts: .byte 4, 5, 6, 7, 255, 255, 255, 255, \ 255, 255, 255, 255, 255, 255, 255, 255 /* L7 : 1 line OK */ +.text + /*****************************************************************************/ From 5d2430f4da3166477a45485ebf146940908fb02e Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 2 Sep 2021 13:17:32 -0500 Subject: [PATCH 18/56] ChangeLog.md: Add missing sub-header for 2.1.2 --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index bcbb0079..74299519 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,8 @@ 2.1.2 ===== +### Significant changes relative to 2.1.1 + 1. Fixed a regression introduced by 2.1 beta1[13] that caused the remaining GAS implementations of AArch64 (Arm 64-bit) Neon SIMD functions (which are used by default with GCC for performance reasons) to be placed in the `.rodata` From 173900b1cabb027495ae530c71250bcedc9925d5 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 2 Sep 2021 12:48:50 -0500 Subject: [PATCH 19/56] tjTrans: Allow 8x8 crop alignmnt w/odd 4:4:4 JPEGs Fixes #549 --- ChangeLog.md | 5 +++++ turbojpeg.c | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 74299519..1a833a86 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -11,6 +11,11 @@ automatically place the `.rodata` section in an executable segment, which prevented libjpeg-turbo from working properly with other linkers and also represented a potential security risk. +2. Fixed an issue whereby the `tjTransform()` function incorrectly computed the +MCU block size for 4:4:4 JPEG images with non-unary sampling factors and thus +unduly rejected some cropping regions, even though those regions aligned with +8x8 MCU block boundaries. + 2.1.1 ===== diff --git a/turbojpeg.c b/turbojpeg.c index 47c59993..4f9e1f60 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -1966,12 +1966,12 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, THROW("tjTransform(): Transform is not perfect"); if (xinfo[i].crop) { - if ((t[i].r.x % xinfo[i].iMCU_sample_width) != 0 || - (t[i].r.y % xinfo[i].iMCU_sample_height) != 0) { + if ((t[i].r.x % tjMCUWidth[jpegSubsamp]) != 0 || + (t[i].r.y % tjMCUHeight[jpegSubsamp]) != 0) { snprintf(this->errStr, JMSG_LENGTH_MAX, "To crop this JPEG image, x must be a multiple of %d\n" "and y must be a multiple of %d.\n", - xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height); + tjMCUWidth[jpegSubsamp], tjMCUHeight[jpegSubsamp]); this->isInstanceError = TRUE; retval = -1; goto bailout; } From 4c313544e2a030e95567246047652f9aabf7b394 Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 20 Sep 2021 16:31:11 -0500 Subject: [PATCH 20/56] AppVeyor: Deploy artifacts to Amazon S3 We would have been perfectly happy for AppVeyor to delete all artifacts other than those from the latest builds in each branch. Instead, they chose to change the global artifact retention policy to 1 month. In addition to being unworkable, that new policy uses more storage than the policy we requested. Lose/lose, so we'll just deploy to S3 like we do with other platforms. --- appveyor.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1e5f5579..de09dd16 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -51,6 +51,8 @@ build_script: move c:\ljt.nightly\files\*.exe . + move c:\ljt.nightly\files\*.html . + move c:\ljt.nightly\log-windows.txt . artifacts: @@ -66,6 +68,20 @@ artifacts: - path: 'log-windows.txt' name: Build log + - path: 'index.html' + name: MD5 checksums + test: off -deploy: off +deploy: + provider: S3 + access_key_id: + secure: Z74OYogQ6bNV/I+6b5ZEXig74+6MW2WLER0v/bPM/uk= + secret_access_key: + secure: cyGZhHVCFwZ9jgf5lXoW69mVtECmqwx3eLo61ha8ueWbMYlHho7lwDXwVvxOFiCa + bucket: libjpeg-turbo-pr + region: + secure: qSElYBgBRcEUf88M6Osthw== + folder: $(APPVEYOR_REPO_BRANCH)/windows + set_public: true + remove_files: true From 739ecbc5ecaeeafe84944263fe8802c2141b8988 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 30 Sep 2021 16:28:51 -0500 Subject: [PATCH 21/56] ChangeLog.md: List CVE ID fixed by 2849d86a --- ChangeLog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 1a833a86..1acbba3e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -41,9 +41,9 @@ metadata. 5. libjpeg-turbo should now build and run on CHERI-enabled architectures, which use capability pointers that are larger than the size of `size_t`. -6. Fixed a regression introduced by 2.1 beta1[5] that caused a segfault in the -64-bit SSE2 Huffman encoder when attempting to losslessly transform a -specially-crafted malformed JPEG image. +6. Fixed a regression (CVE-2021-37972) introduced by 2.1 beta1[5] that caused a +segfault in the 64-bit SSE2 Huffman encoder when attempting to losslessly +transform a specially-crafted malformed JPEG image. 2.1.0 From a9c41fbc4f47be50e9b3bbaae0f26c7b528f9476 Mon Sep 17 00:00:00 2001 From: DRC Date: Sun, 3 Oct 2021 12:43:15 -0500 Subject: [PATCH 22/56] Build: Don't enable Neon SIMD exts with Armv6- When building for 32-bit Arm platforms, test whether basic Neon intrinsics will compile with the specified compiler and C flags. This prevents the build system from enabling the Neon SIMD extensions when targetting Armv6 and other legacy architectures that do not support Neon instructions. Regression introduced by bbd8089297862efb6c39a22b5623f04567ff6443. (Checking whether gas-preprocessor.pl was needed for 32-bit Arm builds had the effect of checking whether Neon instructions were supported.) Fixes #553 --- ChangeLog.md | 4 ++++ simd/CMakeLists.txt | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 1acbba3e..208bbe08 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -16,6 +16,10 @@ MCU block size for 4:4:4 JPEG images with non-unary sampling factors and thus unduly rejected some cropping regions, even though those regions aligned with 8x8 MCU block boundaries. +3. Fixed a regression introduced by 2.1 beta1[13] that caused the build system +to enable the Arm Neon SIMD extensions when targetting Armv6 and other legacy +architectures that do not support Neon instructions. + 2.1.1 ===== diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index e600b1e1..c0e80f3d 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -244,6 +244,17 @@ endif() include(CheckSymbolExists) if(BITS EQUAL 32) set(CMAKE_REQUIRED_FLAGS "-mfpu=neon ${SOFTFP_FLAG}") + check_c_source_compiles(" + #include + int main(int argc, char **argv) { + uint16x8_t input = vdupq_n_u16((uint16_t)argc); + uint8x8_t output = vmovn_u16(input); + return (int)output[0]; + }" HAVE_NEON) + if(NOT HAVE_NEON) + simd_fail("SIMD extensions not available for this architecture") + return() + endif() endif() check_symbol_exists(vld1_s16_x3 arm_neon.h HAVE_VLD1_S16_X3) check_symbol_exists(vld1_u16_x2 arm_neon.h HAVE_VLD1_U16_X2) From 18edeff4e87ab5c2450d81be8eeb0e6f29003756 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Sat, 2 Oct 2021 14:26:57 -0400 Subject: [PATCH 23/56] Build: Set CMP0065 NEW (respect ENABLE_EXPORTS) Referring to https://cmake.org/cmake/help/latest/policy/CMP0065.html, CMake 3.3 and earlier automatically added compiler/linker flags such as -rdynamic/-export-dynamic, which caused symbols to be exported from executables. The primary purpose of this is to allow plugins loaded via dlopen() to access symbols from the calling program. libjpeg-turbo does not need this functionality, and enabling it needlessly increases the size of the libjpeg-turbo executables. Setting CMP0065 to NEW when using CMake 3.4 and later prevents CMake from automatically adding the aforementioned compiler/linker flags unless the ENABLE_EXPORTS property is set for a target (or the CMAKE_ENABLE_EXPORTS variable is set, which causes ENABLE_EXPORTS to be set for all targets.) Closes #554 --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e5dd367..6dd83d3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,9 @@ cmake_minimum_required(VERSION 2.8.12) +# When using CMake 3.4 and later, don't export symbols from executables unless +# the CMAKE_ENABLE_EXPORTS variable is set. +if(POLICY CMP0065) + cmake_policy(SET CMP0065 NEW) +endif() if(CMAKE_EXECUTABLE_SUFFIX) set(CMAKE_EXECUTABLE_SUFFIX_TMP ${CMAKE_EXECUTABLE_SUFFIX}) From 2fd4ae7b2c9dcedf3633d79890dd8bd20ac75e8e Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 27 Oct 2021 14:00:15 -0500 Subject: [PATCH 24/56] JNI: Fix warnings/errors reported by -Xcheck:jni - Don't check for exceptions immediately after invoking the GetPrimitiveArrayCritical() method. That method does not throw exceptions, and checking for them caused -Xcheck:jni to warn about calling other JNI functions in the scope of Get/ReleasePrimitiveArrayCritical(). - Check for exceptions immediately after invoking the CallStaticObjectMethod() method in the PROP2ENV() macro. - Don't use the Get/ReleasePrimitiveArrayCritical() methods for small arrays. -Xcheck:jni didn't complain about that, but there is no performance advantage to using those methods rather than the Get*ArrayRegion() methods for small arrays, and using Get*ArrayRegion() makes the code less error-prone. - Don't release the source/destination planes arrays in the YUV methods until after the corresponding C TurboJPEG functions have returned. --- turbojpeg-jni.c | 166 +++++++++++++++++++++++++----------------------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c index 1b728e3a..4fa6dfdf 100644 --- a/turbojpeg-jni.c +++ b/turbojpeg-jni.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2011-2020 D. R. Commander. All Rights Reserved. + * Copyright (C)2011-2021 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: @@ -44,6 +44,12 @@ } \ } +#define BAILIF0NOEC(f) { \ + if (!(f)) { \ + goto bailout; \ + } \ +} + #define THROW(msg, exceptionClass) { \ jclass _exccls = (*env)->FindClass(env, exceptionClass); \ \ @@ -87,10 +93,12 @@ #endif #define PROP2ENV(property, envvar) { \ - if ((jName = (*env)->NewStringUTF(env, property)) != NULL && \ - (jValue = (*env)->CallStaticObjectMethod(env, cls, mid, \ - jName)) != NULL) { \ - if ((value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \ + if ((jName = (*env)->NewStringUTF(env, property)) != NULL) { \ + jboolean exception; \ + jValue = (*env)->CallStaticObjectMethod(env, cls, mid, jName); \ + exception = (*env)->ExceptionCheck(env); \ + if (jValue && !exception && \ + (value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \ setenv(envvar, value, 1); \ (*env)->ReleaseStringUTFChars(env, jValue, value); \ } \ @@ -242,8 +250,8 @@ static jint TJCompressor_compress if (ProcessSystemProperties(env) < 0) goto bailout; - BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjCompress2(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]], width, pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp, @@ -328,8 +336,7 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanes[3] = { NULL, NULL, NULL }; - int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 }; - int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 }; + int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 }; unsigned char *jpegBuf = NULL; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; @@ -353,15 +360,11 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom if (ProcessSystemProperties(env) < 0) goto bailout; - BAILIF0(srcOffsetsTmp = - (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); - for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i]; - SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp); + (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets); + if ((*env)->ExceptionCheck(env)) goto bailout; - BAILIF0(srcStridesTmp = - (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); - for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i]; - SAFE_RELEASE(jSrcStrides, srcStridesTmp); + (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides); + if ((*env)->ExceptionCheck(env)) goto bailout; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); @@ -379,23 +382,27 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom if ((*env)->GetArrayLength(env, jSrcPlanes[i]) < srcOffsets[i] + planeSize) THROW_ARG("Source plane is not large enough"); - - BAILIF0(srcPlanesTmp[i] = - (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); - srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]]; - SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); } - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + for (i = 0; i < nc; i++) { + BAILIF0NOEC(srcPlanesTmp[i] = + (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); + srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]]; + } + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height, subsamp, &jpegBuf, &jpegSize, jpegQual, flags | TJFLAG_NOREALLOC) == -1) { SAFE_RELEASE(dst, jpegBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); THROW_TJ(); } bailout: SAFE_RELEASE(dst, jpegBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); return (jint)jpegSize; } @@ -410,8 +417,7 @@ static void TJCompressor_encodeYUV jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL }; unsigned char *dstPlanes[3] = { NULL, NULL, NULL }; - int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 }; - int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 }; + int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 }; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; GET_HANDLE(); @@ -436,15 +442,11 @@ static void TJCompressor_encodeYUV if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize) THROW_ARG("Source buffer is not large enough"); - BAILIF0(dstOffsetsTmp = - (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0)); - for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i]; - SAFE_RELEASE(jDstOffsets, dstOffsetsTmp); + (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets); + if ((*env)->ExceptionCheck(env)) goto bailout; - BAILIF0(dstStridesTmp = - (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0)); - for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i]; - SAFE_RELEASE(jDstStrides, dstStridesTmp); + (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides); + if ((*env)->ExceptionCheck(env)) goto bailout; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp); @@ -462,23 +464,27 @@ static void TJCompressor_encodeYUV if ((*env)->GetArrayLength(env, jDstPlanes[i]) < dstOffsets[i] + planeSize) THROW_ARG("Destination plane is not large enough"); - - BAILIF0(dstPlanesTmp[i] = - (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); - dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]]; - SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); } - BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + for (i = 0; i < nc; i++) { + BAILIF0NOEC(dstPlanesTmp[i] = + (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); + dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]]; + } + BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]], width, pitch, height, pf, dstPlanes, dstStrides, subsamp, flags) == -1) { SAFE_RELEASE(src, srcBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); THROW_TJ(); } bailout: SAFE_RELEASE(src, srcBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); } /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */ @@ -533,8 +539,8 @@ static void JNICALL TJCompressor_encodeYUV_12 (jsize)tjBufSizeYUV(width, height, subsamp)) THROW_ARG("Destination buffer is not large enough"); - BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); - BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp, flags) == -1) { @@ -653,7 +659,7 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress if ((*env)->GetArrayLength(env, src) < jpegSize) THROW_ARG("Source buffer is not large enough"); - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width, &height, &jpegSubsamp, &jpegColorspace) == -1) { @@ -701,8 +707,8 @@ static void TJDecompressor_decompress if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize) THROW_ARG("Destination buffer is not large enough"); - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); - BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize, &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width, @@ -780,8 +786,7 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL }; unsigned char *dstPlanes[3] = { NULL, NULL, NULL }; - int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 }; - int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 }; + int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 }; int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0; int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0; tjscalingfactor *sf; @@ -815,15 +820,11 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress if (i >= nsf) THROW_ARG("Could not scale down to desired image dimensions"); - BAILIF0(dstOffsetsTmp = - (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0)); - for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i]; - SAFE_RELEASE(jDstOffsets, dstOffsetsTmp); + (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets); + if ((*env)->ExceptionCheck(env)) goto bailout; - BAILIF0(dstStridesTmp = - (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0)); - for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i]; - SAFE_RELEASE(jDstStrides, dstStridesTmp); + (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides); + if ((*env)->ExceptionCheck(env)) goto bailout; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight, @@ -842,23 +843,27 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress if ((*env)->GetArrayLength(env, jDstPlanes[i]) < dstOffsets[i] + planeSize) THROW_ARG("Destination plane is not large enough"); - - BAILIF0(dstPlanesTmp[i] = - (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); - dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]]; - SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); } - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + for (i = 0; i < nc; i++) { + BAILIF0NOEC(dstPlanesTmp[i] = + (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); + dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]]; + } + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize, dstPlanes, desiredWidth, dstStrides, desiredHeight, flags) == -1) { SAFE_RELEASE(src, jpegBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); THROW_TJ(); } bailout: SAFE_RELEASE(src, jpegBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]); } /* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */ @@ -884,8 +889,8 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress (jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)) THROW_ARG("Destination buffer is not large enough"); - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); - BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0)); + BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf, flags) == -1) { @@ -909,8 +914,7 @@ static void TJDecompressor_decodeYUV jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanes[3] = { NULL, NULL, NULL }; - int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 }; - int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 }; + int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 }; unsigned char *dstBuf = NULL; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; @@ -935,15 +939,11 @@ static void TJDecompressor_decodeYUV if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize) THROW_ARG("Destination buffer is not large enough"); - BAILIF0(srcOffsetsTmp = - (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); - for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i]; - SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp); + (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets); + if ((*env)->ExceptionCheck(env)) goto bailout; - BAILIF0(srcStridesTmp = - (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); - for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i]; - SAFE_RELEASE(jSrcStrides, srcStridesTmp); + (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides); + if ((*env)->ExceptionCheck(env)) goto bailout; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); @@ -961,23 +961,27 @@ static void TJDecompressor_decodeYUV if ((*env)->GetArrayLength(env, jSrcPlanes[i]) < srcOffsets[i] + planeSize) THROW_ARG("Source plane is not large enough"); - - BAILIF0(srcPlanesTmp[i] = - (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); - srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]]; - SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); } - BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); + for (i = 0; i < nc; i++) { + BAILIF0NOEC(srcPlanesTmp[i] = + (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); + srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]]; + } + BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp, &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width, pitch, height, pf, flags) == -1) { SAFE_RELEASE(dst, dstBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); THROW_TJ(); } bailout: SAFE_RELEASE(dst, dstBuf); + for (i = 0; i < nc; i++) + SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]); } /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */ @@ -1183,10 +1187,10 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf tjBufSize(w, h, jpegSubsamp)) THROW_ARG("Destination buffer is not large enough"); } - BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0)); + BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0)); for (i = 0; i < n; i++) - BAILIF0(dstBufs[i] = - (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0)); + BAILIF0NOEC(dstBufs[i] = + (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0)); if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t, flags | TJFLAG_NOREALLOC) == -1) { From d401d6251412a2985810ffaffb90b448a6ee12a9 Mon Sep 17 00:00:00 2001 From: Piotr Kubaj Date: Wed, 27 Oct 2021 03:39:09 +0200 Subject: [PATCH 25/56] PowerPC: Detect AltiVec support on FreeBSD Recent FreeBSD/PowerPC compilers, such as Clang 11.0.x on FreeBSD 13, do the equivalent of passing -maltivec to the compiler by default, so run-time AltiVec detection is unnecessary. However, it becomes necessary when using other compilers or when passing -mno-altivec to the compiler. Closes #552 --- ChangeLog.md | 5 +++++ simd/powerpc/jsimd.c | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 208bbe08..8d9d31aa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,11 @@ unduly rejected some cropping regions, even though those regions aligned with to enable the Arm Neon SIMD extensions when targetting Armv6 and other legacy architectures that do not support Neon instructions. +4. libjpeg-turbo now performs run-time detection of AltiVec instructions on +FreeBSD/PowerPC systems if AltiVec instructions are not enabled at compile +time. This allows both AltiVec-equipped and non-AltiVec-equipped CPUs to be +supported using the same build of libjpeg-turbo. + 2.1.1 ===== diff --git a/simd/powerpc/jsimd.c b/simd/powerpc/jsimd.c index d0d3981e..b9e86dcf 100644 --- a/simd/powerpc/jsimd.c +++ b/simd/powerpc/jsimd.c @@ -35,6 +35,9 @@ #include #include #include +#elif defined(__FreeBSD__) +#include +#include #endif static unsigned int simd_support = ~0; @@ -122,6 +125,8 @@ init_simd(void) int mib[2] = { CTL_MACHDEP, CPU_ALTIVEC }; int altivec; size_t len = sizeof(altivec); +#elif defined(__FreeBSD__) + unsigned long cpufeatures = 0; #endif if (simd_support != ~0U) @@ -144,6 +149,10 @@ init_simd(void) #elif defined(__OpenBSD__) if (sysctl(mib, 2, &altivec, &len, NULL, 0) == 0 && altivec != 0) simd_support |= JSIMD_ALTIVEC; +#elif defined(__FreeBSD__) + elf_aux_info(AT_HWCAP, &cpufeatures, sizeof(cpufeatures)); + if (cpufeatures & PPC_FEATURE_HAS_ALTIVEC) + simd_support |= JSIMD_ALTIVEC; #endif #ifndef NO_GETENV From 4c5fa566b3a95ff01ff04b6f4081f0f0275d1bd3 Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 17 Nov 2021 16:09:50 -0600 Subject: [PATCH 26/56] CI: Halt immediately on all sanitizer errors --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 823e179a..753763fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: run: | mkdir build pushd build - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer" -DENABLE_SHARED=0 .. + cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O1 -g -fsanitize=address,undefined -fno-sanitize-recover=all -fno-omit-frame-pointer" -DENABLE_SHARED=0 .. export NUMCPUS=`grep -c '^processor' /proc/cpuinfo` make -j$NUMCPUS --load-average=$NUMCPUS make test @@ -180,7 +180,7 @@ jobs: run: | mkdir build pushd build - cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O3 -g -fsanitize=memory -fPIE" -DWITH_SIMD=0 .. + cmake -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O3 -g -fsanitize=memory -fno-sanitize-recover=all -fPIE" -DWITH_SIMD=0 .. export NUMCPUS=`grep -c '^processor' /proc/cpuinfo` make -j$NUMCPUS --load-average=$NUMCPUS make test From ecf021bc0d6f435daacff7c35ccaeef0145df1b9 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 18 Nov 2021 21:04:35 -0600 Subject: [PATCH 27/56] cjpeg: Add -strict arg to treat warnings as fatal This adds fault tolerance to the LZW-compressed GIF reader, which is the only compression-side code that can throw warnings. --- ChangeLog.md | 4 ++++ cjpeg.1 | 7 ++++++- cjpeg.c | 22 ++++++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 8d9d31aa..7902d462 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -25,6 +25,10 @@ FreeBSD/PowerPC systems if AltiVec instructions are not enabled at compile time. This allows both AltiVec-equipped and non-AltiVec-equipped CPUs to be supported using the same build of libjpeg-turbo. +5. cjpeg now accepts a `-strict` argument similar to that of djpeg and +jpegtran, which causes the compressor to abort if an LZW-compressed GIF input +image contains incomplete or corrupt image data. + 2.1.1 ===== diff --git a/cjpeg.1 b/cjpeg.1 index 569dc3fa..75a9cce8 100644 --- a/cjpeg.1 +++ b/cjpeg.1 @@ -1,4 +1,4 @@ -.TH CJPEG 1 "4 November 2020" +.TH CJPEG 1 "18 November 2021" .SH NAME cjpeg \- compress an image file to a JPEG file .SH SYNOPSIS @@ -226,6 +226,11 @@ also useful for benchmarking, since it reduces the I/O overhead. .BI \-report Report compression progress. .TP +.BI \-strict +Treat all warnings as fatal. Enabling this option will cause the compressor to +abort if an LZW-compressed GIF input image contains incomplete or corrupt image +data. +.TP .B \-verbose Enable debug printout. More .BR \-v 's diff --git a/cjpeg.c b/cjpeg.c index c99a133e..b299df65 100644 --- a/cjpeg.c +++ b/cjpeg.c @@ -147,6 +147,7 @@ static char *icc_filename; /* for -icc switch */ static char *outfilename; /* for -outfile switch */ boolean memdst; /* for -memdst switch */ boolean report; /* for -report switch */ +boolean strict; /* for -strict switch */ #ifdef CJPEG_FUZZER @@ -240,6 +241,7 @@ usage(void) fprintf(stderr, " -memdst Compress to memory instead of file (useful for benchmarking)\n"); #endif fprintf(stderr, " -report Report compression progress\n"); + fprintf(stderr, " -strict Treat all warnings as fatal\n"); fprintf(stderr, " -verbose or -debug Emit debug output\n"); fprintf(stderr, " -version Print version information and exit\n"); fprintf(stderr, "Switches for wizards:\n"); @@ -285,6 +287,7 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv, outfilename = NULL; memdst = FALSE; report = FALSE; + strict = FALSE; cinfo->err->trace_level = 0; /* Scan command line options, adjust parameters */ @@ -493,6 +496,9 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv, usage(); cinfo->smoothing_factor = val; + } else if (keymatch(arg, "strict", 2)) { + strict = TRUE; + } else if (keymatch(arg, "targa", 1)) { /* Input file is Targa format. */ is_targa = TRUE; @@ -540,6 +546,19 @@ parse_switches(j_compress_ptr cinfo, int argc, char **argv, } +METHODDEF(void) +my_emit_message(j_common_ptr cinfo, int msg_level) +{ + if (msg_level < 0) { + /* Treat warning as fatal */ + cinfo->err->error_exit(cinfo); + } else { + if (cinfo->err->trace_level >= msg_level) + cinfo->err->output_message(cinfo); + } +} + + /* * The main program. */ @@ -600,6 +619,9 @@ main(int argc, char **argv) file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + if (strict) + jerr.emit_message = my_emit_message; + #ifdef TWO_FILE_COMMANDLINE if (!memdst) { /* Must have either -outfile switch or explicit output file name */ From 0f88060b0f6691d955e9a9ca6446374cc57b408a Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 19 Nov 2021 13:36:42 -0600 Subject: [PATCH 28/56] cjpeg.c: Fix fuzzer build failure (caused by previous commit) --- cjpeg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cjpeg.c b/cjpeg.c index b299df65..f4f09ada 100644 --- a/cjpeg.c +++ b/cjpeg.c @@ -166,7 +166,7 @@ void my_error_exit(j_common_ptr cinfo) longjmp(myerr->setjmp_buffer, 1); } -static void my_emit_message(j_common_ptr cinfo, int msg_level) +static void my_emit_message_fuzzer(j_common_ptr cinfo, int msg_level) { if (msg_level < 0) cinfo->err->num_warnings++; @@ -699,7 +699,7 @@ main(int argc, char **argv) #ifdef CJPEG_FUZZER jerr.error_exit = my_error_exit; - jerr.emit_message = my_emit_message; + jerr.emit_message = my_emit_message_fuzzer; if (setjmp(myerr.setjmp_buffer)) HANDLE_ERROR() #endif From 5446ff88d617b2d2768456d9be1a8c47c4606c92 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 19 Nov 2021 13:43:36 -0600 Subject: [PATCH 29/56] CI: CIFuzz integration CIFuzz runs the project's fuzzers for a limited period of time any time a commit is pushed or a PR is submitted. This is not intended to replace OSS-Fuzz but rather to allow us to more quickly catch some fuzzing failures, including fuzzer build regressions like the one introduced in ecf021bc0d6f435daacff7c35ccaeef0145df1b9. Closes #559 --- .github/workflows/cifuzz.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/cifuzz.yml diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml new file mode 100644 index 00000000..3b3964fb --- /dev/null +++ b/.github/workflows/cifuzz.yml @@ -0,0 +1,35 @@ +name: CIFuzz + +on: + push: + branches: + - '**' + tags-ignore: + - '**' + pull_request: + workflow_dispatch: + +jobs: + Fuzzing: + runs-on: ubuntu-latest + steps: + - name: Build Fuzzers + id: build + uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master + with: + oss-fuzz-project-name: 'libjpeg-turbo' + dry-run: false + language: c + - name: Run Fuzzers + uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master + with: + oss-fuzz-project-name: 'libjpeg-turbo' + fuzz-seconds: 600 + language: c + dry-run: false + - name: Upload Crash + uses: actions/upload-artifact@v1 + if: failure() && steps.build.outcome == 'success' + with: + name: artifacts + path: ./out/artifacts From e869a81a7a4be2415f60f29c55d8c5ad7e730aaa Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 23 Nov 2021 09:54:23 -0600 Subject: [PATCH 30/56] jdarith.c: Require cinfo->Se == DCTSIZE2 - 1 This fixes an oversight from the integration of the arithmetic entropy codec from libjpeg (66f97e6820e2cc9ef7429ea36285c80ffda87c8f). I chose to integrate the latest implementation available at the time, which was from jpeg-8b. However, I naively replaced cinfo->lim_Se with DCTSIZE2 - 1, not realizing that-- because of SmartScale-- jpeg-8b contains additional code (https://github.com/libjpeg-turbo/libjpeg-turbo/blob/jpeg-8b/jdinput.c#L249-L334) that guards against illegal values of cinfo->Se >= DCTSIZE2. Thus, libjpeg-turbo's implementation of arithmetic decoding has never guarded against such illegal values. This commit restores the relevant check from the original jpeg-6b arithmetic entropy codec patch ("jpeg-ari", 1e247ac854f8e33682bcfea475f6bccc42377208). Fixes #564 --- jdarith.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdarith.c b/jdarith.c index 7f0d3a78..7887cd96 100644 --- a/jdarith.c +++ b/jdarith.c @@ -698,8 +698,8 @@ bad: /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. * This ought to be an error condition, but we make it a warning. */ - if (cinfo->Ss != 0 || cinfo->Ah != 0 || cinfo->Al != 0 || - (cinfo->Se < DCTSIZE2 && cinfo->Se != DCTSIZE2 - 1)) + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2 - 1 || + cinfo->Ah != 0 || cinfo->Al != 0) WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); /* Select MCU decoding routine */ entropy->pub.decode_mcu = decode_mcu; From 2ce32e0fe53fb402c78c92137998c5119d09aee0 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 30 Nov 2021 10:54:24 -0600 Subject: [PATCH 31/56] cjpeg: automatically compress PGM-->grayscale JPEG (regression introduced by aa7459050d7a50e1d8a99488902d41fbc118a50f) cjpeg sets cinfo.in_color_space to JCS_RGB as an "arbitrary guess." Since tjLoadImage() never uses JCS_RGB, the PGM reader should treat JCS_RGB the same as JCS_UNKNOWN. Fixes #566 --- CMakeLists.txt | 2 +- ChangeLog.md | 10 ++++++++++ rdppm.c | 6 ++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6dd83d3a..a241c83a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if(CMAKE_EXECUTABLE_SUFFIX) endif() project(libjpeg-turbo C) -set(VERSION 2.1.2) +set(VERSION 2.1.3) 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 7902d462..5441bd4a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,13 @@ +2.1.3 +===== + +### Significant changes relative to 2.1.2 + +1. Fixed a regression introduced by 2.0 beta1[7] whereby cjpeg compressed PGM +input files into full-color JPEG images unless the `-grayscale` option was +used. + + 2.1.2 ===== diff --git a/rdppm.c b/rdppm.c index 9699ca5e..a1be3b4b 100644 --- a/rdppm.c +++ b/rdppm.c @@ -603,7 +603,8 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) switch (c) { case '2': /* it's a text-format PGM file */ - if (cinfo->in_color_space == JCS_UNKNOWN) + if (cinfo->in_color_space == JCS_UNKNOWN || + cinfo->in_color_space == JCS_RGB) cinfo->in_color_space = JCS_GRAYSCALE; TRACEMS2(cinfo, 1, JTRC_PGM_TEXT, w, h); if (cinfo->in_color_space == JCS_GRAYSCALE) @@ -631,7 +632,8 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) break; case '5': /* it's a raw-format PGM file */ - if (cinfo->in_color_space == JCS_UNKNOWN) + if (cinfo->in_color_space == JCS_UNKNOWN || + cinfo->in_color_space == JCS_RGB) cinfo->in_color_space = JCS_GRAYSCALE; TRACEMS2(cinfo, 1, JTRC_PGM, w, h); if (maxval > 255) { From 73eff6effe0330caee538e47caa2f0c8f1d715dd Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 30 Nov 2021 15:06:54 -0600 Subject: [PATCH 32/56] cjpeg: auto. compr. gray BMP/GIF-->grayscale JPEG aa7459050d7a50e1d8a99488902d41fbc118a50f was supposed to enable this for BMP input images but didn't, due to a similar oversight to the one fixed in the previous commit. --- ChangeLog.md | 3 +++ cjpeg.1 | 8 ++------ rdbmp.c | 3 ++- rdgif.c | 55 ++++++++++++++++++++++++++++++++++++++-------------- usage.txt | 9 +++------ 5 files changed, 50 insertions(+), 28 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5441bd4a..468bfda4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -7,6 +7,9 @@ input files into full-color JPEG images unless the `-grayscale` option was used. +2. cjpeg now automatically compresses GIF and 8-bit BMP input files into +grayscale JPEG images if the input files contain only shades of gray. + 2.1.2 ===== diff --git a/cjpeg.1 b/cjpeg.1 index 75a9cce8..4bc4c8f9 100644 --- a/cjpeg.1 +++ b/cjpeg.1 @@ -1,4 +1,4 @@ -.TH CJPEG 1 "18 November 2021" +.TH CJPEG 1 "30 November 2021" .SH NAME cjpeg \- compress an image file to a JPEG file .SH SYNOPSIS @@ -40,11 +40,7 @@ Scale quantization tables to adjust image quality. Quality is 0 (worst) to 100 (best); default is 75. (See below for more info.) .TP .B \-grayscale -Create monochrome JPEG file from color input. Be sure to use this switch when -compressing a grayscale BMP or GIF file, because -.B cjpeg -isn't bright enough to notice whether a BMP or GIF file uses only shades of -gray. By saying +Create monochrome JPEG file from color input. By saying .BR \-grayscale, you'll get a smaller JPEG file that takes less time to process. .TP diff --git a/rdbmp.c b/rdbmp.c index 358a0267..99feb4b9 100644 --- a/rdbmp.c +++ b/rdbmp.c @@ -125,7 +125,8 @@ read_colormap(bmp_source_ptr sinfo, int cmaplen, int mapentrysize) break; } - if (sinfo->cinfo->in_color_space == JCS_UNKNOWN && gray) + if ((sinfo->cinfo->in_color_space == JCS_UNKNOWN || + sinfo->cinfo->in_color_space == JCS_RGB) && gray) sinfo->cinfo->in_color_space = JCS_GRAYSCALE; if (sinfo->cinfo->in_color_space == JCS_GRAYSCALE && !gray) diff --git a/rdgif.c b/rdgif.c index c814c6b0..36f0929f 100644 --- a/rdgif.c +++ b/rdgif.c @@ -345,7 +345,7 @@ LOCAL(void) ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap) /* Read a GIF colormap */ { - int i; + int i, gray = 1; for (i = 0; i < cmaplen; i++) { #if BITS_IN_JSAMPLE == 8 @@ -356,6 +356,14 @@ ReadColorMap(gif_source_ptr sinfo, int cmaplen, JSAMPARRAY cmap) cmap[CM_RED][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); cmap[CM_GREEN][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); cmap[CM_BLUE][i] = (JSAMPLE)UPSCALE(ReadByte(sinfo)); + if (cmap[CM_RED][i] != cmap[CM_GREEN][i] || + cmap[CM_GREEN][i] != cmap[CM_BLUE][i]) + gray = 0; + } + + if (sinfo->cinfo->in_color_space == JCS_RGB && gray) { + sinfo->cinfo->in_color_space = JCS_GRAYSCALE; + sinfo->cinfo->input_components = 1; } } @@ -516,10 +524,15 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) source->pub.get_pixel_rows = get_pixel_rows; } + if (cinfo->in_color_space != JCS_GRAYSCALE) { + cinfo->in_color_space = JCS_RGB; + cinfo->input_components = NUMCOLORS; + } + /* Create compressor input buffer. */ source->pub.buffer = (*cinfo->mem->alloc_sarray) - ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)width * NUMCOLORS, - (JDIMENSION)1); + ((j_common_ptr)cinfo, JPOOL_IMAGE, + (JDIMENSION)width * cinfo->input_components, (JDIMENSION)1); source->pub.buffer_height = 1; /* Pad colormap for safety. */ @@ -530,8 +543,6 @@ start_input_gif(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) } /* Return info about the image. */ - cinfo->in_color_space = JCS_RGB; - cinfo->input_components = NUMCOLORS; cinfo->data_precision = BITS_IN_JSAMPLE; /* we always rescale data to this */ cinfo->image_width = width; cinfo->image_height = height; @@ -556,11 +567,18 @@ get_pixel_rows(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) register JSAMPARRAY colormap = source->colormap; ptr = source->pub.buffer[0]; - for (col = cinfo->image_width; col > 0; col--) { - c = LZWReadByte(source); - *ptr++ = colormap[CM_RED][c]; - *ptr++ = colormap[CM_GREEN][c]; - *ptr++ = colormap[CM_BLUE][c]; + if (cinfo->in_color_space == JCS_GRAYSCALE) { + for (col = cinfo->image_width; col > 0; col--) { + c = LZWReadByte(source); + *ptr++ = colormap[CM_RED][c]; + } + } else { + for (col = cinfo->image_width; col > 0; col--) { + c = LZWReadByte(source); + *ptr++ = colormap[CM_RED][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE][c]; + } } return 1; } @@ -646,11 +664,18 @@ get_interlaced_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) FALSE); /* Scan the row, expand colormap, and output */ ptr = source->pub.buffer[0]; - for (col = cinfo->image_width; col > 0; col--) { - c = *sptr++; - *ptr++ = colormap[CM_RED][c]; - *ptr++ = colormap[CM_GREEN][c]; - *ptr++ = colormap[CM_BLUE][c]; + if (cinfo->in_color_space == JCS_GRAYSCALE) { + for (col = cinfo->image_width; col > 0; col--) { + c = *sptr++; + *ptr++ = colormap[CM_RED][c]; + } + } else { + for (col = cinfo->image_width; col > 0; col--) { + c = *sptr++; + *ptr++ = colormap[CM_RED][c]; + *ptr++ = colormap[CM_GREEN][c]; + *ptr++ = colormap[CM_BLUE][c]; + } } source->cur_row_number++; /* for next time */ return 1; diff --git a/usage.txt b/usage.txt index b60a593f..bc2253f1 100644 --- a/usage.txt +++ b/usage.txt @@ -72,12 +72,9 @@ The basic command line switches for cjpeg are: Quality is 0 (worst) to 100 (best); default is 75. (See below for more info.) - -grayscale Create monochrome JPEG file from color input. - Be sure to use this switch when compressing a grayscale - BMP or GIF file, because cjpeg isn't bright enough to - notice whether a BMP or GIF file uses only shades of - gray. By saying -grayscale, you'll get a smaller JPEG - file that takes less time to process. + -grayscale Create monochrome JPEG file from color input. By + saying -grayscale, you'll get a smaller JPEG file that + takes less time to process. -rgb Create RGB JPEG file. Using this switch suppresses the conversion from RGB From 8a9a6dd15abccf0e51d9ce848b8be90cb621eed0 Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 1 Dec 2021 09:02:36 -0600 Subject: [PATCH 33/56] Make incompatible feature errs more user-friendly - Use JERR_NOTIMPL ("Not implemented yet") rather than JERR_NOT_COMPILED ("Requested feature was omitted at compile time") to indicate that arithmetic coding is incompatible with Huffman table optimization. This is more consistent with other parts of the libjpeg API code. JERR_NOT_COMPILED is typically used to indicate that a major feature was not compiled in, whereas JERR_NOTIMPL is typically used to indicate that two features were compiled in but are incompatible with each other (such as, for instance, two-pass color quantization and partial image decompression.) - Change the text of JERR_NOTIMPL to "Requested features are incompatible". This is a more accurate description of the situation. "Not implemented yet" implies that it may be possible to support the requested combination of features in the future, but that is not true in most of the cases where JERR_NOTIMPL is used. Fixes #567 --- jcarith.c | 4 ++-- jerror.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jcarith.c b/jcarith.c index b6d093f7..812dff90 100644 --- a/jcarith.c +++ b/jcarith.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Developed 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015, 2018, D. R. Commander. + * Copyright (C) 2015, 2018, 2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -836,7 +836,7 @@ start_pass(j_compress_ptr cinfo, boolean gather_statistics) * We are fully adaptive here and need no extra * statistics gathering pass! */ - ERREXIT(cinfo, JERR_NOT_COMPILED); + ERREXIT(cinfo, JERR_NOTIMPL); /* We assume jcmaster.c already validated the progressive scan parameters. */ diff --git a/jerror.h b/jerror.h index 4476df2c..133fd3f1 100644 --- a/jerror.h +++ b/jerror.h @@ -5,7 +5,7 @@ * Copyright (C) 1994-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2014, 2017, D. R. Commander. + * Copyright (C) 2014, 2017, 2021, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -103,7 +103,7 @@ JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, "Cannot transcode due to multiple use of quantization table %d") JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") -JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOTIMPL, "Requested features are incompatible") JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") #if JPEG_LIB_VERSION >= 70 JMESSAGE(JERR_NO_ARITH_TABLE, "Arithmetic table 0x%02x was not defined") From 57ba02a408a9a55ccff25aae8b164632a3a4f177 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 1 Oct 2021 16:28:54 -0500 Subject: [PATCH 34/56] Build: Improve Neon capability detection - Use check_c_source_compiles() rather than check_symbol_exists() to detect the presence of vld1_s16_x3(), vld1_u16_x2(), and vld1q_u8_x4(). check_symbol_exists() is unreliable for detecting intrinsics, and in practice, it did not detect the presence of the aforementioned intrinsics in versions of GCC that support them. - Set DEFAULT_NEON_INTRINSICS=0 for GCC < 12, even if the aforementioned intrinsics are available. The AArch64 back end in GCC 10 and 11 supports the necessary intrinsics, but the GAS implementation is still faster when using those compilers. Fixes #547 --- ChangeLog.md | 3 ++ simd/CMakeLists.txt | 68 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 468bfda4..6ceacd54 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -10,6 +10,9 @@ used. 2. cjpeg now automatically compresses GIF and 8-bit BMP input files into grayscale JPEG images if the input files contain only shades of gray. +3. The build system now enables the intrinsics implementation of the AArch64 +(Arm 64-bit) Neon SIMD extensions by default when using GCC 12 or later. + 2.1.2 ===== diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index c0e80f3d..cdfb95c2 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -241,7 +241,6 @@ if(BITS EQUAL 32) endif() endif() -include(CheckSymbolExists) if(BITS EQUAL 32) set(CMAKE_REQUIRED_FLAGS "-mfpu=neon ${SOFTFP_FLAG}") check_c_source_compiles(" @@ -256,23 +255,68 @@ if(BITS EQUAL 32) return() endif() endif() -check_symbol_exists(vld1_s16_x3 arm_neon.h HAVE_VLD1_S16_X3) -check_symbol_exists(vld1_u16_x2 arm_neon.h HAVE_VLD1_U16_X2) -check_symbol_exists(vld1q_u8_x4 arm_neon.h HAVE_VLD1Q_U8_X4) +check_c_source_compiles(" + #include + int main(int argc, char **argv) { + const int16_t input[] = { + (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, + (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, + (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc + }; + int16x4x3_t output = vld1_s16_x3(input); + return (int)output.val[0][0]; + }" HAVE_VLD1_S16_X3) +check_c_source_compiles(" + #include + int main(int argc, char **argv) { + const uint16_t input[] = { + (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, + (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc + }; + uint16x4x2_t output = vld1_u16_x2(input); + return (int)output.val[0][0]; + }" HAVE_VLD1_U16_X2) +check_c_source_compiles(" + #include + int main(int argc, char **argv) { + const uint8_t input[] = { + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, + (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc + }; + uint8x16x4_t output = vld1q_u8_x4(input); + return (int)output.val[0][0]; + }" HAVE_VLD1Q_U8_X4) if(BITS EQUAL 32) unset(CMAKE_REQUIRED_FLAGS) endif() configure_file(arm/neon-compat.h.in arm/neon-compat.h @ONLY) include_directories(${CMAKE_CURRENT_BINARY_DIR}/arm) -# GCC (as of this writing) and some older versions of Clang do not have a full -# or optimal set of Neon intrinsics, so for performance reasons, when using -# those compilers, we default to using the older GAS implementation of the Neon -# SIMD extensions for certain algorithms. The presence or absence of the three -# intrinsics we tested above is a reasonable proxy for this. We always default -# to using the full Neon intrinsics implementation when building for macOS or -# iOS, to avoid the need for gas-preprocessor. -if((HAVE_VLD1_S16_X3 AND HAVE_VLD1_U16_X2 AND HAVE_VLD1Q_U8_X4) OR APPLE) +# GCC 11 and earlier and some older versions of Clang do not have a full or +# optimal set of Neon intrinsics, so for performance reasons, when using those +# compilers, we default to using the older GAS implementation of the Neon SIMD +# extensions for certain algorithms. The presence or absence of the three +# intrinsics we tested above is a reasonable proxy for this, except with GCC 10 +# and 11. We always default to using the full Neon intrinsics implementation +# when building for macOS or iOS, to avoid the need for gas-preprocessor. +if((HAVE_VLD1_S16_X3 AND HAVE_VLD1_U16_X2 AND HAVE_VLD1Q_U8_X4 AND + (NOT CMAKE_COMPILER_IS_GNUCC OR + CMAKE_C_COMPILER_VERSION VERSION_EQUAL 12.0.0 OR + CMAKE_C_COMPILER_VERSION VERSION_GREATER 12.0.0)) OR APPLE) set(DEFAULT_NEON_INTRINSICS 1) else() set(DEFAULT_NEON_INTRINSICS 0) From a01857cff6a2b7b3283ef1d0ecb6b01d06b597f8 Mon Sep 17 00:00:00 2001 From: DRC Date: Wed, 1 Dec 2021 17:08:29 -0600 Subject: [PATCH 35/56] Build: Disallow NEON_INTRINSICS=0 if GAS is broken If NEON_INTRINSICS=0, then run the GAS sanity check from libjpeg-turbo 2.0.x and force-enable NEON_INTRINSICS if the test fails. This fixes the AArch32 build when using Clang 6.0 on Linux or the Clang toolchain in the Android NDK r15*-r16*. It also prevents users from manually disabling NEON_INTRINSICS if doing so would break the build (such as with Xcode 5.) --- simd/CMakeLists.txt | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index cdfb95c2..8606174e 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -311,12 +311,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}/arm) # compilers, we default to using the older GAS implementation of the Neon SIMD # extensions for certain algorithms. The presence or absence of the three # intrinsics we tested above is a reasonable proxy for this, except with GCC 10 -# and 11. We always default to using the full Neon intrinsics implementation -# when building for macOS or iOS, to avoid the need for gas-preprocessor. +# and 11. if((HAVE_VLD1_S16_X3 AND HAVE_VLD1_U16_X2 AND HAVE_VLD1Q_U8_X4 AND (NOT CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL 12.0.0 OR - CMAKE_C_COMPILER_VERSION VERSION_GREATER 12.0.0)) OR APPLE) + CMAKE_C_COMPILER_VERSION VERSION_GREATER 12.0.0))) set(DEFAULT_NEON_INTRINSICS 1) else() set(DEFAULT_NEON_INTRINSICS 0) @@ -324,6 +323,40 @@ endif() option(NEON_INTRINSICS "Because GCC (as of this writing) and some older versions of Clang do not have a full or optimal set of Neon intrinsics, for performance reasons, the default when building libjpeg-turbo with those compilers is to continue using the older GAS implementation of the Neon SIMD extensions for certain algorithms. Setting this option forces the full Neon intrinsics implementation to be used with all compilers. Unsetting this option forces the hybrid GAS/intrinsics implementation to be used with all compilers." ${DEFAULT_NEON_INTRINSICS}) +if(NOT NEON_INTRINSICS) + enable_language(ASM) + + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ASM_FLAGS}") + + # Test whether gas-preprocessor.pl would be needed to build the GAS + # implementation of the Neon SIMD extensions. If so, then automatically + # enable the full Neon intrinsics implementation. + if(CPU_TYPE STREQUAL "arm") + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gastest.S " + .text + .fpu neon + .arch armv7a + .object_arch armv4 + .arm + pld [r0] + vmovn.u16 d0, q0") + else() + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/gastest.S " + .text + MYVAR .req x0 + movi v0.16b, #100 + mov MYVAR, #100 + .unreq MYVAR") + endif() + separate_arguments(CMAKE_ASM_FLAGS_SEP UNIX_COMMAND "${CMAKE_ASM_FLAGS}") + execute_process(COMMAND ${CMAKE_ASM_COMPILER} ${CMAKE_ASM_FLAGS_SEP} + -x assembler-with-cpp -c ${CMAKE_CURRENT_BINARY_DIR}/gastest.S + RESULT_VARIABLE RESULT OUTPUT_VARIABLE OUTPUT ERROR_VARIABLE ERROR) + if(NOT RESULT EQUAL 0) + message(WARNING "GAS appears to be broken. Using the full Neon SIMD intrinsics implementation.") + set(NEON_INTRINSICS 1 CACHE INTERNAL "" FORCE) + endif() +endif() boolean_number(NEON_INTRINSICS PARENT_SCOPE) if(NEON_INTRINSICS) add_definitions(-DNEON_INTRINSICS) @@ -349,10 +382,6 @@ if(BITS EQUAL 32) set_source_files_properties(${SIMD_SOURCES} COMPILE_FLAGS "-mfpu=neon ${SOFTFP_FLAG}") endif() if(NOT NEON_INTRINSICS) - enable_language(ASM) - - set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_ASM_FLAGS}") - string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UC) set(EFFECTIVE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${CMAKE_ASM_FLAGS_${CMAKE_BUILD_TYPE_UC}}") message(STATUS "CMAKE_ASM_FLAGS = ${EFFECTIVE_ASM_FLAGS}") From a7f0244e9bf31233918388cc0321e01ccc07ba5c Mon Sep 17 00:00:00 2001 From: Dmitry Tsarevich Date: Thu, 6 Jan 2022 02:21:10 +0300 Subject: [PATCH 36/56] turbojpeg.h: Parenthesize TJSCALED() dimension arg This ensures that, for example, TJSCALED(dim0 + dim1, sf) will evaluate to (((dim0 + dim1) * sf.num + sf.denom - 1) / sf.denom) rather than ((dim0 + (dim1 * sf.num) + sf.denom - 1) / sf.denom) --- turbojpeg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/turbojpeg.h b/turbojpeg.h index c2f6b514..5b33ad84 100644 --- a/turbojpeg.h +++ b/turbojpeg.h @@ -673,7 +673,7 @@ typedef void *tjhandle; * scalingFactor). */ #define TJSCALED(dimension, scalingFactor) \ - ((dimension * scalingFactor.num + scalingFactor.denom - 1) / \ + (((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \ scalingFactor.denom) From 172972394a51352d0b67c30f20041e69a98d78b7 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 6 Jan 2022 09:17:30 -0600 Subject: [PATCH 37/56] Eliminate non-ANSI C compatibility macros libjpeg-turbo has never supported non-ANSI C compilers. Per the spec, ANSI C compilers must have locale.h, stddef.h, stdlib.h, memset(), memcpy(), unsigned char, and unsigned short. They must also handle undefined structures. --- CMakeLists.txt | 28 ---------------------------- LICENSE.md | 2 +- cjpeg.c | 5 ----- djpeg.c | 4 ---- jcapimin.c | 6 +++--- jcarith.c | 10 +++++----- jchuff.c | 22 +++++++++++----------- jconfig.h.in | 31 ------------------------------- jconfig.txt | 44 -------------------------------------------- jcphuff.c | 6 +++--- jcprepct.c | 8 ++++---- jctrans.c | 6 +++--- jdapimin.c | 6 +++--- jdarith.c | 10 +++++----- jdatadst-tj.c | 8 ++------ jdatadst.c | 9 ++------- jddctmgr.c | 4 ++-- jdicc.c | 4 ---- jdinput.c | 4 ++-- jdmarker.c | 8 ++++---- jdmaster.c | 12 ++++++------ jinclude.h | 41 ----------------------------------------- jmemmgr.c | 6 ------ jmemnobs.c | 5 ----- jmorecfg.h | 4 ---- jpegint.h | 9 --------- jstdhuff.c | 9 +++++---- jutils.c | 10 +++++----- jversion.h | 6 +++--- rdbmp.c | 6 +++--- rdjpgcom.c | 6 ------ rdppm.c | 6 +++--- rdswitch.c | 4 ++-- transupp.c | 44 +++++++++++++++++++++++--------------------- turbojpeg.c | 16 ++++++++-------- win/jconfig.h.in | 8 -------- wrbmp.c | 14 +++++++------- wrgif.c | 4 ++-- wrjpgcom.c | 3 --- wrppm.c | 4 ++-- wrtarga.c | 6 +++--- 41 files changed, 122 insertions(+), 326 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a241c83a..bb6efcf4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -406,34 +406,6 @@ if(MSVC) endif() if(UNIX) - # Check for headers - check_include_files(locale.h HAVE_LOCALE_H) - check_include_files(stddef.h HAVE_STDDEF_H) - check_include_files(stdlib.h HAVE_STDLIB_H) - check_include_files(sys/types.h NEED_SYS_TYPES_H) - - # Check for functions - include(CheckSymbolExists) - check_symbol_exists(memset string.h HAVE_MEMSET) - check_symbol_exists(memcpy string.h HAVE_MEMCPY) - if(NOT HAVE_MEMSET AND NOT HAVE_MEMCPY) - set(NEED_BSD_STRINGS 1) - endif() - - # Check for types - check_type_size("unsigned char" UNSIGNED_CHAR) - check_type_size("unsigned short" UNSIGNED_SHORT) - - # Check for compiler features - check_c_source_compiles("int main(void) { typedef struct undefined_structure *undef_struct_ptr; undef_struct_ptr ptr = 0; return ptr != 0; }" - INCOMPLETE_TYPES) - if(INCOMPLETE_TYPES) - message(STATUS "Compiler supports pointers to undefined structures.") - else() - set(INCOMPLETE_TYPES_BROKEN 1) - message(STATUS "Compiler does not support pointers to undefined structures.") - endif() - if(CMAKE_CROSSCOMPILING) set(RIGHT_SHIFT_IS_UNSIGNED 0) else() diff --git a/LICENSE.md b/LICENSE.md index a1cdad52..d753e1d7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -91,7 +91,7 @@ best of our understanding. The Modified (3-clause) BSD License =================================== -Copyright (C)2009-2021 D. R. Commander. All Rights Reserved.
+Copyright (C)2009-2022 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 diff --git a/cjpeg.c b/cjpeg.c index f4f09ada..41ef5c18 100644 --- a/cjpeg.c +++ b/cjpeg.c @@ -34,11 +34,6 @@ #include "jversion.h" /* for version message */ #include "jconfigint.h" -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void *malloc(size_t size); -extern void free(void *ptr); -#endif - #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ #ifdef __MWERKS__ #include /* Metrowerks needs this */ diff --git a/djpeg.c b/djpeg.c index d47984e6..d02a2183 100644 --- a/djpeg.c +++ b/djpeg.c @@ -32,10 +32,6 @@ #include "jversion.h" /* for version message */ #include "jconfigint.h" -#ifndef HAVE_STDLIB_H /* should declare free() */ -extern void free(void *ptr); -#endif - #include /* to declare isprint() */ #ifdef USE_CCOMMAND /* command-line reader for Macintosh */ diff --git a/jcapimin.c b/jcapimin.c index 178c55ba..84e7ecc9 100644 --- a/jcapimin.c +++ b/jcapimin.c @@ -4,8 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1998, Thomas G. Lane. * Modified 2003-2010 by Guido Vollbeding. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -52,7 +52,7 @@ jpeg_CreateCompress(j_compress_ptr cinfo, int version, size_t structsize) { struct jpeg_error_mgr *err = cinfo->err; void *client_data = cinfo->client_data; /* ignore Purify complaint here */ - MEMZERO(cinfo, sizeof(struct jpeg_compress_struct)); + memset(cinfo, 0, sizeof(struct jpeg_compress_struct)); cinfo->err = err; cinfo->client_data = client_data; } diff --git a/jcarith.c b/jcarith.c index 812dff90..b1720521 100644 --- a/jcarith.c +++ b/jcarith.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Developed 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015, 2018, 2021, D. R. Commander. + * Copyright (C) 2015, 2018, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -338,14 +338,14 @@ emit_restart(j_compress_ptr cinfo, int restart_num) compptr = cinfo->cur_comp_info[ci]; /* DC needs no table for refinement scan */ if (cinfo->progressive_mode == 0 || (cinfo->Ss == 0 && cinfo->Ah == 0)) { - MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + memset(entropy->dc_stats[compptr->dc_tbl_no], 0, DC_STAT_BINS); /* Reset DC predictions to 0 */ entropy->last_dc_val[ci] = 0; entropy->dc_context[ci] = 0; } /* AC needs no table when not present */ if (cinfo->progressive_mode == 0 || cinfo->Se) { - MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + memset(entropy->ac_stats[compptr->ac_tbl_no], 0, AC_STAT_BINS); } } @@ -867,7 +867,7 @@ start_pass(j_compress_ptr cinfo, boolean gather_statistics) if (entropy->dc_stats[tbl] == NULL) entropy->dc_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, DC_STAT_BINS); - MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + memset(entropy->dc_stats[tbl], 0, DC_STAT_BINS); /* Initialize DC predictions to 0 */ entropy->last_dc_val[ci] = 0; entropy->dc_context[ci] = 0; @@ -880,7 +880,7 @@ start_pass(j_compress_ptr cinfo, boolean gather_statistics) if (entropy->ac_stats[tbl] == NULL) entropy->ac_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, AC_STAT_BINS); - MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); + memset(entropy->ac_stats[tbl], 0, AC_STAT_BINS); #ifdef CALCULATE_SPECTRAL_CONDITIONING if (cinfo->progressive_mode) /* Section G.1.3.2: Set appropriate arithmetic conditioning value Kx */ diff --git a/jchuff.c b/jchuff.c index 8ff817b1..f4dfa1cb 100644 --- a/jchuff.c +++ b/jchuff.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2014-2016, 2018-2021, D. R. Commander. + * Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander. * Copyright (C) 2015, Matthieu Darbois. * Copyright (C) 2018, Matthias Räncker. * Copyright (C) 2020, Arm Limited. @@ -200,12 +200,12 @@ start_pass_huff(j_compress_ptr cinfo, boolean gather_statistics) entropy->dc_count_ptrs[dctbl] = (long *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, 257 * sizeof(long)); - MEMZERO(entropy->dc_count_ptrs[dctbl], 257 * sizeof(long)); + memset(entropy->dc_count_ptrs[dctbl], 0, 257 * sizeof(long)); if (entropy->ac_count_ptrs[actbl] == NULL) entropy->ac_count_ptrs[actbl] = (long *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, 257 * sizeof(long)); - MEMZERO(entropy->ac_count_ptrs[actbl], 257 * sizeof(long)); + memset(entropy->ac_count_ptrs[actbl], 0, 257 * sizeof(long)); #endif } else { /* Compute derived values for Huffman tables */ @@ -315,8 +315,8 @@ jpeg_make_c_derived_tbl(j_compress_ptr cinfo, boolean isDC, int tblno, * this lets us detect duplicate VAL entries here, and later * allows emit_bits to detect any attempt to emit such symbols. */ - MEMZERO(dtbl->ehufco, sizeof(dtbl->ehufco)); - MEMZERO(dtbl->ehufsi, sizeof(dtbl->ehufsi)); + memset(dtbl->ehufco, 0, sizeof(dtbl->ehufco)); + memset(dtbl->ehufsi, 0, sizeof(dtbl->ehufsi)); /* This is also a convenient place to check for out-of-range * and duplicated VAL entries. We allow 0..255 for AC symbols @@ -478,7 +478,7 @@ dump_buffer(working_state *state) buffer = _buffer; \ while (bytes > 0) { \ bytestocopy = MIN(bytes, state->free_in_buffer); \ - MEMCOPY(state->next_output_byte, buffer, bytestocopy); \ + memcpy(state->next_output_byte, buffer, bytestocopy); \ state->next_output_byte += bytestocopy; \ buffer += bytestocopy; \ state->free_in_buffer -= bytestocopy; \ @@ -941,8 +941,8 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[]) /* This algorithm is explained in section K.2 of the JPEG standard */ - MEMZERO(bits, sizeof(bits)); - MEMZERO(codesize, sizeof(codesize)); + memset(bits, 0, sizeof(bits)); + memset(codesize, 0, sizeof(codesize)); for (i = 0; i < 257; i++) others[i] = -1; /* init links to empty */ @@ -1044,7 +1044,7 @@ jpeg_gen_optimal_table(j_compress_ptr cinfo, JHUFF_TBL *htbl, long freq[]) bits[i]--; /* Return final symbol counts (only for lengths 0..16) */ - MEMCOPY(htbl->bits, bits, sizeof(htbl->bits)); + memcpy(htbl->bits, bits, sizeof(htbl->bits)); /* Return a list of the symbols sorted by code length */ /* It's not real clear to me why we don't need to consider the codelength @@ -1083,8 +1083,8 @@ finish_pass_gather(j_compress_ptr cinfo) /* It's important not to apply jpeg_gen_optimal_table more than once * per table, because it clobbers the input frequency counts! */ - MEMZERO(did_dc, sizeof(did_dc)); - MEMZERO(did_ac, sizeof(did_ac)); + memset(did_dc, 0, sizeof(did_dc)); + memset(did_ac, 0, sizeof(did_ac)); for (ci = 0; ci < cinfo->comps_in_scan; ci++) { compptr = cinfo->cur_comp_info[ci]; diff --git a/jconfig.h.in b/jconfig.h.in index d4284d97..e0180122 100644 --- a/jconfig.h.in +++ b/jconfig.h.in @@ -32,37 +32,6 @@ #define BITS_IN_JSAMPLE @BITS_IN_JSAMPLE@ /* use 8 or 12 */ -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_LOCALE_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDDEF_H 1 - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_STDLIB_H 1 - -/* Define if you need to include to get size_t. */ -#cmakedefine NEED_SYS_TYPES_H 1 - -/* Define if you have BSD-like bzero and bcopy in rather than - memset/memcpy in . */ -#cmakedefine NEED_BSD_STRINGS 1 - -/* Define to 1 if the system has the type `unsigned char'. */ -#cmakedefine HAVE_UNSIGNED_CHAR 1 - -/* Define to 1 if the system has the type `unsigned short'. */ -#cmakedefine HAVE_UNSIGNED_SHORT 1 - -/* Compiler does not support pointers to undefined structures. */ -#cmakedefine INCOMPLETE_TYPES_BROKEN 1 - /* Define if your (broken) compiler shifts signed values as if they were unsigned. */ #cmakedefine RIGHT_SHIFT_IS_UNSIGNED 1 - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `unsigned int' if does not define. */ -/* #undef size_t */ diff --git a/jconfig.txt b/jconfig.txt index 21f35c13..d593da9e 100644 --- a/jconfig.txt +++ b/jconfig.txt @@ -26,50 +26,6 @@ * #define the symbol if yes, #undef it if no. */ -/* Does your compiler support the declaration "unsigned char" ? - * How about "unsigned short" ? - */ -#define HAVE_UNSIGNED_CHAR -#define HAVE_UNSIGNED_SHORT - -/* Define "void" as "char" if your compiler doesn't know about type void. - * NOTE: be sure to define void such that "void *" represents the most general - * pointer type, e.g., that returned by malloc(). - */ -/* #define void char */ - -/* Define "const" as empty if your compiler doesn't know the "const" keyword. - */ -/* #define const */ - -/* Define this if your system has an ANSI-conforming file. - */ -#define HAVE_STDDEF_H - -/* Define this if your system has an ANSI-conforming file. - */ -#define HAVE_STDLIB_H - -/* Define this if your system does not have an ANSI/SysV , - * but does have a BSD-style . - */ -#undef NEED_BSD_STRINGS - -/* Define this if your system does not provide typedef size_t in any of the - * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in - * instead. - */ -#undef NEED_SYS_TYPES_H - -/* Although a real ANSI C compiler can deal perfectly well with pointers to - * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI - * and pseudo-ANSI compilers get confused. To keep one of these bozos happy, - * define INCOMPLETE_TYPES_BROKEN. This is not recommended unless you - * actually get "missing structure definition" warnings or errors while - * compiling the JPEG code. - */ -#undef INCOMPLETE_TYPES_BROKEN - /* Define "boolean" as unsigned char, not int, on Windows systems. */ #ifdef _WIN32 diff --git a/jcphuff.c b/jcphuff.c index 11019871..156ae634 100644 --- a/jcphuff.c +++ b/jcphuff.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1995-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2011, 2015, 2018, 2021, D. R. Commander. + * Copyright (C) 2011, 2015, 2018, 2021-2022, D. R. Commander. * Copyright (C) 2016, 2018, Matthieu Darbois. * Copyright (C) 2020, Arm Limited. * Copyright (C) 2021, Alex Richardson. @@ -275,7 +275,7 @@ start_pass_phuff(j_compress_ptr cinfo, boolean gather_statistics) entropy->count_ptrs[tbl] = (long *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, 257 * sizeof(long)); - MEMZERO(entropy->count_ptrs[tbl], 257 * sizeof(long)); + memset(entropy->count_ptrs[tbl], 0, 257 * sizeof(long)); } else { /* Compute derived values for Huffman table */ /* We may do this more than once for a table, but it's not expensive */ @@ -1062,7 +1062,7 @@ finish_pass_gather_phuff(j_compress_ptr cinfo) /* It's important not to apply jpeg_gen_optimal_table more than once * per table, because it clobbers the input frequency counts! */ - MEMZERO(did, sizeof(did)); + memset(did, 0, sizeof(did)); for (ci = 0; ci < cinfo->comps_in_scan; ci++) { compptr = cinfo->cur_comp_info[ci]; diff --git a/jcprepct.c b/jcprepct.c index d59713ae..f27cc345 100644 --- a/jcprepct.c +++ b/jcprepct.c @@ -3,8 +3,8 @@ * * This file is part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -289,8 +289,8 @@ create_context_buffer(j_compress_ptr cinfo) cinfo->max_h_samp_factor) / compptr->h_samp_factor), (JDIMENSION)(3 * rgroup_height)); /* Copy true buffer row pointers into the middle of the fake row array */ - MEMCOPY(fake_buffer + rgroup_height, true_buffer, - 3 * rgroup_height * sizeof(JSAMPROW)); + memcpy(fake_buffer + rgroup_height, true_buffer, + 3 * rgroup_height * sizeof(JSAMPROW)); /* Fill in the above and below wraparound pointers */ for (i = 0; i < rgroup_height; i++) { fake_buffer[i] = true_buffer[2 * rgroup_height + i]; diff --git a/jctrans.c b/jctrans.c index ab6a2186..e121028e 100644 --- a/jctrans.c +++ b/jctrans.c @@ -5,7 +5,7 @@ * Copyright (C) 1995-1998, Thomas G. Lane. * Modified 2000-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2020, D. R. Commander. + * Copyright (C) 2020, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -100,8 +100,8 @@ jpeg_copy_critical_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo) qtblptr = &dstinfo->quant_tbl_ptrs[tblno]; if (*qtblptr == NULL) *qtblptr = jpeg_alloc_quant_table((j_common_ptr)dstinfo); - MEMCOPY((*qtblptr)->quantval, srcinfo->quant_tbl_ptrs[tblno]->quantval, - sizeof((*qtblptr)->quantval)); + memcpy((*qtblptr)->quantval, srcinfo->quant_tbl_ptrs[tblno]->quantval, + sizeof((*qtblptr)->quantval)); (*qtblptr)->sent_table = FALSE; } } diff --git a/jdapimin.c b/jdapimin.c index 4609b132..f50c27ed 100644 --- a/jdapimin.c +++ b/jdapimin.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1998, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2016, D. R. Commander. + * Copyright (C) 2016, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -53,7 +53,7 @@ jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize) { struct jpeg_error_mgr *err = cinfo->err; void *client_data = cinfo->client_data; /* ignore Purify complaint here */ - MEMZERO(cinfo, sizeof(struct jpeg_decompress_struct)); + memset(cinfo, 0, sizeof(struct jpeg_decompress_struct)); cinfo->err = err; cinfo->client_data = client_data; } @@ -92,7 +92,7 @@ jpeg_CreateDecompress(j_decompress_ptr cinfo, int version, size_t structsize) cinfo->master = (struct jpeg_decomp_master *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(my_decomp_master)); - MEMZERO(cinfo->master, sizeof(my_decomp_master)); + memset(cinfo->master, 0, sizeof(my_decomp_master)); } diff --git a/jdarith.c b/jdarith.c index 7887cd96..431b46cd 100644 --- a/jdarith.c +++ b/jdarith.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Developed 1997-2015 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015-2020, D. R. Commander. + * Copyright (C) 2015-2020, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -210,13 +210,13 @@ process_restart(j_decompress_ptr cinfo) for (ci = 0; ci < cinfo->comps_in_scan; ci++) { compptr = cinfo->cur_comp_info[ci]; if (!cinfo->progressive_mode || (cinfo->Ss == 0 && cinfo->Ah == 0)) { - MEMZERO(entropy->dc_stats[compptr->dc_tbl_no], DC_STAT_BINS); + memset(entropy->dc_stats[compptr->dc_tbl_no], 0, DC_STAT_BINS); /* Reset DC predictions to 0 */ entropy->last_dc_val[ci] = 0; entropy->dc_context[ci] = 0; } if (!cinfo->progressive_mode || cinfo->Ss) { - MEMZERO(entropy->ac_stats[compptr->ac_tbl_no], AC_STAT_BINS); + memset(entropy->ac_stats[compptr->ac_tbl_no], 0, AC_STAT_BINS); } } @@ -715,7 +715,7 @@ bad: if (entropy->dc_stats[tbl] == NULL) entropy->dc_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, DC_STAT_BINS); - MEMZERO(entropy->dc_stats[tbl], DC_STAT_BINS); + memset(entropy->dc_stats[tbl], 0, DC_STAT_BINS); /* Initialize DC predictions to 0 */ entropy->last_dc_val[ci] = 0; entropy->dc_context[ci] = 0; @@ -727,7 +727,7 @@ bad: if (entropy->ac_stats[tbl] == NULL) entropy->ac_stats[tbl] = (unsigned char *)(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, AC_STAT_BINS); - MEMZERO(entropy->ac_stats[tbl], AC_STAT_BINS); + memset(entropy->ac_stats[tbl], 0, AC_STAT_BINS); } } diff --git a/jdatadst-tj.c b/jdatadst-tj.c index fdaa2de1..e10d9812 100644 --- a/jdatadst-tj.c +++ b/jdatadst-tj.c @@ -5,7 +5,7 @@ * Copyright (C) 1994-1996, Thomas G. Lane. * Modified 2009-2012 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2011, 2014, 2016, 2019, D. R. Commander. + * Copyright (C) 2011, 2014, 2016, 2019, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -23,10 +23,6 @@ #include "jpeglib.h" #include "jerror.h" -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void *malloc(size_t size); -extern void free(void *ptr); -#endif void jpeg_mem_dest_tj(j_compress_ptr cinfo, unsigned char **outbuffer, unsigned long *outsize, boolean alloc); @@ -101,7 +97,7 @@ empty_mem_output_buffer(j_compress_ptr cinfo) if (nextbuffer == NULL) ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); - MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); + memcpy(nextbuffer, dest->buffer, dest->bufsize); free(dest->newbuffer); diff --git a/jdatadst.c b/jdatadst.c index 246fffb5..fe8c0543 100644 --- a/jdatadst.c +++ b/jdatadst.c @@ -5,7 +5,7 @@ * Copyright (C) 1994-1996, Thomas G. Lane. * Modified 2009-2012 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2013, 2016, D. R. Commander. + * Copyright (C) 2013, 2016, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -23,11 +23,6 @@ #include "jpeglib.h" #include "jerror.h" -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void *malloc(size_t size); -extern void free(void *ptr); -#endif - /* Expanded data destination object for stdio output */ @@ -141,7 +136,7 @@ empty_mem_output_buffer(j_compress_ptr cinfo) if (nextbuffer == NULL) ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 10); - MEMCOPY(nextbuffer, dest->buffer, dest->bufsize); + memcpy(nextbuffer, dest->buffer, dest->bufsize); free(dest->newbuffer); diff --git a/jddctmgr.c b/jddctmgr.c index 266f4466..e78d7beb 100644 --- a/jddctmgr.c +++ b/jddctmgr.c @@ -6,7 +6,7 @@ * Modified 2002-2010 by Guido Vollbeding. * libjpeg-turbo Modifications: * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2010, 2015, D. R. Commander. + * Copyright (C) 2010, 2015, 2022, D. R. Commander. * Copyright (C) 2013, MIPS Technologies, Inc., California. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -345,7 +345,7 @@ jinit_inverse_dct(j_decompress_ptr cinfo) compptr->dct_table = (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(multiplier_table)); - MEMZERO(compptr->dct_table, sizeof(multiplier_table)); + memset(compptr->dct_table, 0, sizeof(multiplier_table)); /* Mark multiplier table not yet set up for any method */ idct->cur_method[ci] = -1; } diff --git a/jdicc.c b/jdicc.c index a1a5b867..50aa9a96 100644 --- a/jdicc.c +++ b/jdicc.c @@ -18,10 +18,6 @@ #include "jpeglib.h" #include "jerror.h" -#ifndef HAVE_STDLIB_H /* should declare malloc() */ -extern void *malloc(size_t size); -#endif - #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ diff --git a/jdinput.c b/jdinput.c index deec618f..1bc5aff1 100644 --- a/jdinput.c +++ b/jdinput.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2016, 2018, D. R. Commander. + * Copyright (C) 2010, 2016, 2018, 2022, D. R. Commander. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -264,7 +264,7 @@ latch_quant_tables(j_decompress_ptr cinfo) qtbl = (JQUANT_TBL *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(JQUANT_TBL)); - MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], sizeof(JQUANT_TBL)); + memcpy(qtbl, cinfo->quant_tbl_ptrs[qtblno], sizeof(JQUANT_TBL)); compptr->quant_table = qtbl; } } diff --git a/jdmarker.c b/jdmarker.c index b964c3a1..f7eba615 100644 --- a/jdmarker.c +++ b/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, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -473,7 +473,7 @@ get_dht(j_decompress_ptr cinfo) for (i = 0; i < count; i++) INPUT_BYTE(cinfo, huffval[i], return FALSE); - MEMZERO(&huffval[count], (256 - count) * sizeof(UINT8)); + memset(&huffval[count], 0, (256 - count) * sizeof(UINT8)); length -= count; @@ -491,8 +491,8 @@ get_dht(j_decompress_ptr cinfo) if (*htblptr == NULL) *htblptr = jpeg_alloc_huff_table((j_common_ptr)cinfo); - MEMCOPY((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); - MEMCOPY((*htblptr)->huffval, huffval, sizeof((*htblptr)->huffval)); + memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); + memcpy((*htblptr)->huffval, huffval, sizeof((*htblptr)->huffval)); } if (length != 0) diff --git a/jdmaster.c b/jdmaster.c index cbc8774b..a3690bf5 100644 --- a/jdmaster.c +++ b/jdmaster.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2002-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2016, 2019, D. R. Commander. + * Copyright (C) 2009-2011, 2016, 2019, 2022, D. R. Commander. * Copyright (C) 2013, Linaro Limited. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg @@ -417,7 +417,7 @@ prepare_range_limit_table(j_decompress_ptr cinfo) table += (MAXJSAMPLE + 1); /* allow negative subscripts of simple table */ cinfo->sample_range_limit = table; /* First segment of "simple" table: limit[x] = 0 for x < 0 */ - MEMZERO(table - (MAXJSAMPLE + 1), (MAXJSAMPLE + 1) * sizeof(JSAMPLE)); + memset(table - (MAXJSAMPLE + 1), 0, (MAXJSAMPLE + 1) * sizeof(JSAMPLE)); /* Main part of "simple" table: limit[x] = x */ for (i = 0; i <= MAXJSAMPLE; i++) table[i] = (JSAMPLE)i; @@ -426,10 +426,10 @@ prepare_range_limit_table(j_decompress_ptr cinfo) for (i = CENTERJSAMPLE; i < 2 * (MAXJSAMPLE + 1); i++) table[i] = MAXJSAMPLE; /* Second half of post-IDCT table */ - MEMZERO(table + (2 * (MAXJSAMPLE + 1)), - (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); - MEMCOPY(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE), - cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); + memset(table + (2 * (MAXJSAMPLE + 1)), 0, + (2 * (MAXJSAMPLE + 1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); + memcpy(table + (4 * (MAXJSAMPLE + 1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); } diff --git a/jinclude.h b/jinclude.h index c1bcf7d9..23248767 100644 --- a/jinclude.h +++ b/jinclude.h @@ -24,57 +24,16 @@ #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* - * We need the NULL macro and size_t typedef. - * On an ANSI-conforming system it is sufficient to include . - * Otherwise, we get them from or ; we may have to - * pull in as well. * Note that the core JPEG library does not require ; * only the default error handler and data source/destination modules do. * But we must pull it in because of the references to FILE in jpeglib.h. * You can remove those references if you want to compile without . */ -#ifdef HAVE_STDDEF_H #include -#endif - -#ifdef HAVE_STDLIB_H #include -#endif - -#ifdef NEED_SYS_TYPES_H -#include -#endif - #include - -/* - * We need memory copying and zeroing functions, plus strncpy(). - * ANSI and System V implementations declare these in . - * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). - * Some systems may declare memset and memcpy in . - * - * NOTE: we assume the size parameters to these functions are of type size_t. - * Change the casts in these macros if not! - */ - -#ifdef NEED_BSD_STRINGS - -#include -#define MEMZERO(target, size) \ - bzero((void *)(target), (size_t)(size)) -#define MEMCOPY(dest, src, size) \ - bcopy((const void *)(src), (void *)(dest), (size_t)(size)) - -#else /* not BSD, assume ANSI/SysV string lib */ - #include -#define MEMZERO(target, size) \ - memset((void *)(target), 0, (size_t)(size)) -#define MEMCOPY(dest, src, size) \ - memcpy((void *)(dest), (const void *)(src), (size_t)(size)) - -#endif /* * The modules that use fread() and fwrite() always invoke them through diff --git a/jmemmgr.c b/jmemmgr.c index 70b8ec0c..d053813d 100644 --- a/jmemmgr.c +++ b/jmemmgr.c @@ -37,12 +37,6 @@ #endif #include -#ifndef NO_GETENV -#ifndef HAVE_STDLIB_H /* should declare getenv() */ -extern char *getenv(const char *name); -#endif -#endif - LOCAL(size_t) round_up_pow2(size_t a, size_t b) diff --git a/jmemnobs.c b/jmemnobs.c index 089be8f5..cd6571ba 100644 --- a/jmemnobs.c +++ b/jmemnobs.c @@ -22,11 +22,6 @@ #include "jpeglib.h" #include "jmemsys.h" /* import the system-dependent declarations */ -#ifndef HAVE_STDLIB_H /* should declare malloc(),free() */ -extern void *malloc(size_t size); -extern void free(void *ptr); -#endif - /* * Memory allocation and freeing are controlled by the regular library diff --git a/jmorecfg.h b/jmorecfg.h index fb3a9cf4..b33a9919 100644 --- a/jmorecfg.h +++ b/jmorecfg.h @@ -100,11 +100,7 @@ typedef unsigned char UINT8; /* UINT16 must hold at least the values 0..65535. */ -#ifdef HAVE_UNSIGNED_SHORT typedef unsigned short UINT16; -#else /* not HAVE_UNSIGNED_SHORT */ -typedef unsigned int UINT16; -#endif /* HAVE_UNSIGNED_SHORT */ /* INT16 must hold at least the values -32768..32767. */ diff --git a/jpegint.h b/jpegint.h index 8c853479..6af9e2a1 100644 --- a/jpegint.h +++ b/jpegint.h @@ -373,12 +373,3 @@ extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ /* Arithmetic coding probability estimation tables in jaricom.c */ extern const JLONG jpeg_aritab[]; - -/* Suppress undefined-structure complaints if necessary. */ - -#ifdef INCOMPLETE_TYPES_BROKEN -#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ -struct jvirt_sarray_control { long dummy; }; -struct jvirt_barray_control { long dummy; }; -#endif -#endif /* INCOMPLETE_TYPES_BROKEN */ diff --git a/jstdhuff.c b/jstdhuff.c index 036d6495..345b513d 100644 --- a/jstdhuff.c +++ b/jstdhuff.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) 2013, D. R. Commander. + * Copyright (C) 2013, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -29,7 +29,7 @@ add_huff_table(j_common_ptr cinfo, JHUFF_TBL **htblptr, const UINT8 *bits, return; /* Copy the number-of-symbols-of-each-code-length counts */ - MEMCOPY((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); + memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits)); /* Validate the counts. We do this here mainly so we can copy the right * number of symbols from the val[] array, without risking marching off @@ -41,8 +41,9 @@ add_huff_table(j_common_ptr cinfo, JHUFF_TBL **htblptr, const UINT8 *bits, if (nsymbols < 1 || nsymbols > 256) ERREXIT(cinfo, JERR_BAD_HUFF_TABLE); - MEMCOPY((*htblptr)->huffval, val, nsymbols * sizeof(UINT8)); - MEMZERO(&((*htblptr)->huffval[nsymbols]), (256 - nsymbols) * sizeof(UINT8)); + memcpy((*htblptr)->huffval, val, nsymbols * sizeof(UINT8)); + memset(&((*htblptr)->huffval[nsymbols]), 0, + (256 - nsymbols) * sizeof(UINT8)); /* Initialize sent_table FALSE so table will be written to JPEG file. */ (*htblptr)->sent_table = FALSE; diff --git a/jutils.c b/jutils.c index 5c5bb17d..d8627162 100644 --- a/jutils.c +++ b/jutils.c @@ -3,8 +3,8 @@ * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1996, Thomas G. Lane. - * It was modified by The libjpeg-turbo Project to include only code - * relevant to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -110,7 +110,7 @@ jcopy_sample_rows(JSAMPARRAY input_array, int source_row, for (row = num_rows; row > 0; row--) { inptr = *input_array++; outptr = *output_array++; - MEMCOPY(outptr, inptr, count); + memcpy(outptr, inptr, count); } } @@ -120,7 +120,7 @@ jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks) /* Copy a row of coefficient blocks from one place to another. */ { - MEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * sizeof(JCOEF))); + memcpy(output_row, input_row, num_blocks * (DCTSIZE2 * sizeof(JCOEF))); } @@ -129,5 +129,5 @@ jzero_far(void *target, size_t bytestozero) /* Zero out a chunk of memory. */ /* This might be sample-array data, block-array data, or alloc_large data. */ { - MEMZERO(target, bytestozero); + memset(target, 0, bytestozero); } diff --git a/jversion.h b/jversion.h index 2ab534af..63db95b9 100644 --- a/jversion.h +++ b/jversion.h @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2012-2021, D. R. Commander. + * Copyright (C) 2010, 2012-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -37,7 +37,7 @@ */ #define JCOPYRIGHT \ - "Copyright (C) 2009-2021 D. R. Commander\n" \ + "Copyright (C) 2009-2022 D. R. Commander\n" \ "Copyright (C) 2015, 2020 Google, Inc.\n" \ "Copyright (C) 2019-2020 Arm Limited\n" \ "Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \ @@ -51,4 +51,4 @@ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding" #define JCOPYRIGHT_SHORT \ - "Copyright (C) 1991-2021 The libjpeg-turbo Project and many others" + "Copyright (C) 1991-2022 The libjpeg-turbo Project and many others" diff --git a/rdbmp.c b/rdbmp.c index 99feb4b9..0124f4d2 100644 --- a/rdbmp.c +++ b/rdbmp.c @@ -6,7 +6,7 @@ * Modified 2009-2017 by Guido Vollbeding. * libjpeg-turbo Modifications: * Modified 2011 by Siarhei Siamashka. - * Copyright (C) 2015, 2017-2018, 2021, D. R. Commander. + * Copyright (C) 2015, 2017-2018, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -246,7 +246,7 @@ get_24bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) */ outptr = source->pub.buffer[0]; if (cinfo->in_color_space == JCS_EXT_BGR) { - MEMCOPY(outptr, inptr, source->row_width); + memcpy(outptr, inptr, source->row_width); } else if (cinfo->in_color_space == JCS_CMYK) { for (col = cinfo->image_width; col > 0; col--) { JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++; @@ -310,7 +310,7 @@ get_32bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) outptr = source->pub.buffer[0]; if (cinfo->in_color_space == JCS_EXT_BGRX || cinfo->in_color_space == JCS_EXT_BGRA) { - MEMCOPY(outptr, inptr, source->row_width); + memcpy(outptr, inptr, source->row_width); } else if (cinfo->in_color_space == JCS_CMYK) { for (col = cinfo->image_width; col > 0; col--) { JSAMPLE b = *inptr++, g = *inptr++, r = *inptr++; diff --git a/rdjpgcom.c b/rdjpgcom.c index 620270e1..76736d74 100644 --- a/rdjpgcom.c +++ b/rdjpgcom.c @@ -18,9 +18,7 @@ #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ #include "jinclude.h" /* get auto-config symbols, */ -#ifdef HAVE_LOCALE_H #include /* Bill Allombert: use locale for isprint */ -#endif #include /* to declare isupper(), tolower() */ #ifdef USE_SETMODE #include /* to declare setmode()'s parameter macros */ @@ -223,9 +221,7 @@ process_COM(int raw) int lastch = 0; /* Bill Allombert: set locale properly for isprint */ -#ifdef HAVE_LOCALE_H setlocale(LC_CTYPE, ""); -#endif /* Get the marker parameter length count */ length = read_2_bytes(); @@ -261,9 +257,7 @@ process_COM(int raw) printf("\n"); /* Bill Allombert: revert to C locale */ -#ifdef HAVE_LOCALE_H setlocale(LC_CTYPE, "C"); -#endif } diff --git a/rdppm.c b/rdppm.c index a1be3b4b..cd6f9a4e 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, 2020-2021, D. R. Commander. + * Copyright (C) 2015-2017, 2020-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -732,8 +732,8 @@ start_input_ppm(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, (size_t)(((long)MAX(maxval, 255) + 1L) * sizeof(JSAMPLE))); - MEMZERO(source->rescale, (size_t)(((long)MAX(maxval, 255) + 1L) * - sizeof(JSAMPLE))); + memset(source->rescale, 0, (size_t)(((long)MAX(maxval, 255) + 1L) * + sizeof(JSAMPLE))); half_maxval = maxval / 2; for (val = 0; val <= (long)maxval; val++) { /* The multiplication here must be done in 32 bits to avoid overflow */ diff --git a/rdswitch.c b/rdswitch.c index 886fec39..f9ed70f5 100644 --- a/rdswitch.c +++ b/rdswitch.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2018, D. R. Commander. + * Copyright (C) 2010, 2018, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -263,7 +263,7 @@ bogus: scanptr = (jpeg_scan_info *) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, scanno * sizeof(jpeg_scan_info)); - MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info)); + memcpy(scanptr, scans, scanno * sizeof(jpeg_scan_info)); cinfo->scan_info = scanptr; cinfo->num_scans = scanno; } diff --git a/transupp.c b/transupp.c index ce30ab7b..a3d878cc 100644 --- a/transupp.c +++ b/transupp.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2017, 2021, D. R. Commander. + * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -262,8 +262,8 @@ do_drop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, } } else { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(dst_buffer[offset_y] + x_drop_blocks, - comp_width * sizeof(JBLOCK)); + memset(dst_buffer[offset_y] + x_drop_blocks, 0, + comp_width * sizeof(JBLOCK)); } } } @@ -345,8 +345,8 @@ do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, if (dst_blk_y < y_crop_blocks || dst_blk_y >= y_crop_blocks + comp_height) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(dst_buffer[offset_y], - compptr->width_in_blocks * sizeof(JBLOCK)); + memset(dst_buffer[offset_y], 0, + compptr->width_in_blocks * sizeof(JBLOCK)); } continue; } @@ -363,14 +363,14 @@ do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (dstinfo->_jpeg_width > srcinfo->output_width) { if (x_crop_blocks > 0) { - MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK)); + memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK)); } jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y] + x_crop_blocks, comp_width); if (compptr->width_in_blocks > x_crop_blocks + comp_width) { - MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width, - (compptr->width_in_blocks - x_crop_blocks - comp_width) * - sizeof(JBLOCK)); + memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0, + (compptr->width_in_blocks - x_crop_blocks - comp_width) * + sizeof(JBLOCK)); } } else { jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, @@ -421,8 +421,8 @@ do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, if (dst_blk_y < y_crop_blocks || dst_blk_y >= y_crop_blocks + comp_height) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(dst_buffer[offset_y], - compptr->width_in_blocks * sizeof(JBLOCK)); + memset(dst_buffer[offset_y], 0, + compptr->width_in_blocks * sizeof(JBLOCK)); } continue; } @@ -438,7 +438,7 @@ do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (x_crop_blocks > 0) { - MEMZERO(dst_buffer[offset_y], x_crop_blocks * sizeof(JBLOCK)); + memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK)); dc = src_buffer[offset_y][0][0]; for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) { dst_buffer[offset_y][dst_blk_x][0] = dc; @@ -447,9 +447,9 @@ do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jcopy_block_row(src_buffer[offset_y], dst_buffer[offset_y] + x_crop_blocks, comp_width); if (compptr->width_in_blocks > x_crop_blocks + comp_width) { - MEMZERO(dst_buffer[offset_y] + x_crop_blocks + comp_width, - (compptr->width_in_blocks - x_crop_blocks - comp_width) * - sizeof(JBLOCK)); + memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0, + (compptr->width_in_blocks - x_crop_blocks - comp_width) * + sizeof(JBLOCK)); dc = src_buffer[offset_y][comp_width - 1][0]; for (dst_blk_x = x_crop_blocks + comp_width; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { @@ -502,8 +502,8 @@ do_crop_ext_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, if (dst_blk_y < y_crop_blocks || dst_blk_y >= y_crop_blocks + comp_height) { for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(dst_buffer[offset_y], - compptr->width_in_blocks * sizeof(JBLOCK)); + memset(dst_buffer[offset_y], 0, + compptr->width_in_blocks * sizeof(JBLOCK)); } continue; } @@ -591,7 +591,8 @@ do_wipe(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks, (JDIMENSION)compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK)); + memset(buffer[offset_y] + x_wipe_blocks, 0, + wipe_width * sizeof(JBLOCK)); } } } @@ -626,7 +627,8 @@ do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks, (JDIMENSION)compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { - MEMZERO(buffer[offset_y] + x_wipe_blocks, wipe_width * sizeof(JBLOCK)); + memset(buffer[offset_y] + x_wipe_blocks, 0, + wipe_width * sizeof(JBLOCK)); if (x_wipe_blocks > 0) { dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0]; if (wipe_right < compptr->width_in_blocks) { @@ -709,8 +711,8 @@ do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo, } } } else { - MEMZERO(buffer[offset_y] + x_wipe_blocks, - wipe_width * sizeof(JBLOCK)); + memset(buffer[offset_y] + x_wipe_blocks, 0, + wipe_width * sizeof(JBLOCK)); } } } diff --git a/turbojpeg.c b/turbojpeg.c index 4f9e1f60..a6888a20 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2009-2021 D. R. Commander. All Rights Reserved. + * Copyright (C)2009-2022 D. R. Commander. All Rights Reserved. * Copyright (C)2021 Alex Richardson. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without @@ -514,7 +514,7 @@ DLLEXPORT tjhandle tjInitCompress(void) "tjInitCompress(): Memory allocation failure"); return NULL; } - MEMZERO(this, sizeof(tjinstance)); + memset(this, 0, sizeof(tjinstance)); snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); return _tjInitCompress(this); } @@ -1186,7 +1186,7 @@ DLLEXPORT tjhandle tjInitDecompress(void) "tjInitDecompress(): Memory allocation failure"); return NULL; } - MEMZERO(this, sizeof(tjinstance)); + memset(this, 0, sizeof(tjinstance)); snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); return _tjInitDecompress(this); } @@ -1301,7 +1301,7 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, #endif if (flags & TJFLAG_LIMITSCANS) { - MEMZERO(&progress, sizeof(struct my_progress_mgr)); + memset(&progress, 0, sizeof(struct my_progress_mgr)); progress.pub.progress_monitor = my_progress_monitor; progress.this = this; dinfo->progress = &progress.pub; @@ -1649,7 +1649,7 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle, #endif if (flags & TJFLAG_LIMITSCANS) { - MEMZERO(&progress, sizeof(struct my_progress_mgr)); + memset(&progress, 0, sizeof(struct my_progress_mgr)); progress.pub.progress_monitor = my_progress_monitor; progress.this = this; dinfo->progress = &progress.pub; @@ -1877,7 +1877,7 @@ DLLEXPORT tjhandle tjInitTransform(void) "tjInitTransform(): Memory allocation failure"); return NULL; } - MEMZERO(this, sizeof(tjinstance)); + memset(this, 0, sizeof(tjinstance)); snprintf(this->errStr, JMSG_LENGTH_MAX, "No error"); handle = _tjInitCompress(this); if (!handle) return NULL; @@ -1912,7 +1912,7 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, #endif if (flags & TJFLAG_LIMITSCANS) { - MEMZERO(&progress, sizeof(struct my_progress_mgr)); + memset(&progress, 0, sizeof(struct my_progress_mgr)); progress.pub.progress_monitor = my_progress_monitor; progress.this = this; dinfo->progress = &progress.pub; @@ -1922,7 +1922,7 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, if ((xinfo = (jpeg_transform_info *)malloc(sizeof(jpeg_transform_info) * n)) == NULL) THROW("tjTransform(): Memory allocation failure"); - MEMZERO(xinfo, sizeof(jpeg_transform_info) * n); + memset(xinfo, 0, sizeof(jpeg_transform_info) * n); if (setjmp(this->jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ diff --git a/win/jconfig.h.in b/win/jconfig.h.in index 13cceef0..0fca77b2 100644 --- a/win/jconfig.h.in +++ b/win/jconfig.h.in @@ -9,14 +9,6 @@ #define BITS_IN_JSAMPLE @BITS_IN_JSAMPLE@ /* use 8 or 12 */ -#define HAVE_STDDEF_H -#define HAVE_STDLIB_H -#undef NEED_SYS_TYPES_H -#undef NEED_BSD_STRINGS - -#define HAVE_UNSIGNED_CHAR -#define HAVE_UNSIGNED_SHORT -#undef INCOMPLETE_TYPES_BROKEN #undef RIGHT_SHIFT_IS_UNSIGNED /* Define "boolean" as unsigned char, not int, per Windows custom */ diff --git a/wrbmp.c b/wrbmp.c index 408a722a..56a53a44 100644 --- a/wrbmp.c +++ b/wrbmp.c @@ -5,7 +5,7 @@ * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: * Copyright (C) 2013, Linaro Limited. - * Copyright (C) 2014-2015, 2017, 2019, D. R. Commander. + * Copyright (C) 2014-2015, 2017, 2019, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -121,7 +121,7 @@ put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, inptr = dest->pub.buffer[0]; if (cinfo->out_color_space == JCS_EXT_BGR) { - MEMCOPY(outptr, inptr, dest->row_width); + memcpy(outptr, inptr, dest->row_width); outptr += cinfo->output_width * 3; } else if (cinfo->out_color_space == JCS_RGB565) { boolean big_endian = is_big_endian(); @@ -191,7 +191,7 @@ put_gray_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, /* Transfer data. */ inptr = dest->pub.buffer[0]; - MEMCOPY(outptr, inptr, cinfo->output_width); + memcpy(outptr, inptr, cinfo->output_width); outptr += cinfo->output_width; /* Zero out the pad bytes. */ @@ -256,8 +256,8 @@ write_bmp_header(j_decompress_ptr cinfo, bmp_dest_ptr dest) bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height; /* Set unused fields of header to 0 */ - MEMZERO(bmpfileheader, sizeof(bmpfileheader)); - MEMZERO(bmpinfoheader, sizeof(bmpinfoheader)); + memset(bmpfileheader, 0, sizeof(bmpfileheader)); + memset(bmpinfoheader, 0, sizeof(bmpinfoheader)); /* Fill the file header */ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ @@ -325,8 +325,8 @@ write_os2_header(j_decompress_ptr cinfo, bmp_dest_ptr dest) bfSize = headersize + (long)dest->row_width * (long)cinfo->output_height; /* Set unused fields of header to 0 */ - MEMZERO(bmpfileheader, sizeof(bmpfileheader)); - MEMZERO(bmpcoreheader, sizeof(bmpcoreheader)); + memset(bmpfileheader, 0, sizeof(bmpfileheader)); + memset(bmpcoreheader, 0, sizeof(bmpcoreheader)); /* Fill the file header */ bmpfileheader[0] = 0x42; /* first 2 bytes are ASCII 'B', 'M' */ diff --git a/wrgif.c b/wrgif.c index 82a24291..bac672c6 100644 --- a/wrgif.c +++ b/wrgif.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2015-2019 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2015, 2017, D. R. Commander. + * Copyright (C) 2015, 2017, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -169,7 +169,7 @@ clear_hash(gif_dest_ptr dinfo) /* Fill the hash table with empty entries */ { /* It's sufficient to zero hash_code[] */ - MEMZERO(dinfo->hash_code, HSIZE * sizeof(code_int)); + memset(dinfo->hash_code, 0, HSIZE * sizeof(code_int)); } diff --git a/wrjpgcom.c b/wrjpgcom.c index 8a4e7416..6a4dc6bc 100644 --- a/wrjpgcom.c +++ b/wrjpgcom.c @@ -17,9 +17,6 @@ #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ #include "jinclude.h" /* get auto-config symbols, */ -#ifndef HAVE_STDLIB_H /* should declare malloc() */ -extern void *malloc(); -#endif #include /* to declare isupper(), tolower() */ #ifdef USE_SETMODE #include /* to declare setmode()'s parameter macros */ diff --git a/wrppm.c b/wrppm.c index 3081ec33..ffa4f89e 100644 --- a/wrppm.c +++ b/wrppm.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1996, Thomas G. Lane. * Modified 2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2017, 2019-2020, D. R. Commander. + * Copyright (C) 2017, 2019-2020, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -115,7 +115,7 @@ copy_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, ptr = dest->pub.buffer[0]; bufferptr = dest->iobuffer; #if BITS_IN_JSAMPLE == 8 - MEMCOPY(bufferptr, ptr, dest->samples_per_row); + memcpy(bufferptr, ptr, dest->samples_per_row); #else for (col = dest->samples_per_row; col > 0; col--) { PUTPPMSAMPLE(bufferptr, *ptr++); diff --git a/wrtarga.c b/wrtarga.c index 7a654ff5..57c6a2ff 100644 --- a/wrtarga.c +++ b/wrtarga.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2017, 2019, D. R. Commander. + * Copyright (C) 2017, 2019, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -51,7 +51,7 @@ write_header(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) char targaheader[18]; /* Set unused fields of header to 0 */ - MEMZERO(targaheader, sizeof(targaheader)); + memset(targaheader, 0, sizeof(targaheader)); if (num_colors > 0) { targaheader[1] = 1; /* color map type 1 */ @@ -121,7 +121,7 @@ put_gray_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, inptr = dest->pub.buffer[0]; outptr = dest->iobuffer; - MEMCOPY(outptr, inptr, cinfo->output_width); + memcpy(outptr, inptr, cinfo->output_width); (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); } From 1f55ae7b0fa3acc348a630171617d0e56d922b68 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 6 Jan 2022 12:08:46 -0600 Subject: [PATCH 38/56] Fix -Wpedantic compiler warnings ... and test for those warnings (and others) when performing CI builds. --- .github/workflows/build.yml | 12 +++++++++--- cdjpeg.c | 4 ++-- djpeg.c | 12 ++++++------ rdjpgcom.c | 6 +++--- rdppm.c | 16 ++++++++-------- turbojpeg.c | 14 +++++++------- 6 files changed, 35 insertions(+), 29 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 753763fa..da292845 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -119,7 +119,9 @@ jobs: run: | mkdir build pushd build - cmake -G"Unix Makefiles" -DWITH_12BIT=1 .. + cmake -G"Unix Makefiles" -DWITH_12BIT=1 \ + -DCMAKE_C_FLAGS='--std=gnu90 -Wall -Werror -Wextra -Wpedantic -pedantic-errors -Wdouble-promotion -Wformat-overflow=2 -Wformat-security -Wformat-signedness -Wformat-truncation=2 -Wformat-y2k -Wmissing-include-dirs -Wshift-overflow=2 -Wswitch-bool -Wno-unused-parameter -Wuninitialized -Wstrict-overflow=2 -Wstringop-overflow=4 -Wstringop-truncation -Wduplicated-branches -Wduplicated-cond -Wdeclaration-after-statement -Wshadow -Wunsafe-loop-optimizations -Wundef -Wcast-align -Wno-clobbered -Wjump-misses-init -Wno-sign-compare -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wdisabled-optimization -Wno-overlength-strings' \ + .. export NUMCPUS=`grep -c '^processor' /proc/cpuinfo` make -j$NUMCPUS --load-average=$NUMCPUS make test @@ -139,7 +141,9 @@ jobs: run: | mkdir build pushd build - cmake -G"Unix Makefiles" -DWITH_JPEG7=1 -DCMAKE_C_FLAGS=-mx32 .. + cmake -G"Unix Makefiles" -DWITH_JPEG7=1 -DCMAKE_C_FLAGS=-mx32 \ + -DCMAKE_C_FLAGS='--std=gnu90 -Wall -Werror -Wextra -Wpedantic -pedantic-errors -Wdouble-promotion -Wformat-overflow=2 -Wformat-security -Wformat-signedness -Wformat-truncation=2 -Wformat-y2k -Wmissing-include-dirs -Wshift-overflow=2 -Wswitch-bool -Wno-unused-parameter -Wuninitialized -Wstrict-overflow=2 -Wstringop-overflow=4 -Wstringop-truncation -Wduplicated-branches -Wduplicated-cond -Wdeclaration-after-statement -Wshadow -Wunsafe-loop-optimizations -Wundef -Wcast-align -Wno-clobbered -Wjump-misses-init -Wno-sign-compare -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wdisabled-optimization -Wno-overlength-strings' \ + .. export NUMCPUS=`grep -c '^processor' /proc/cpuinfo` make -j$NUMCPUS --load-average=$NUMCPUS make test @@ -161,7 +165,9 @@ jobs: run: | mkdir build pushd build - cmake -G"Unix Makefiles" -DWITH_JPEG8=1 .. + cmake -G"Unix Makefiles" -DWITH_JPEG8=1 \ + -DCMAKE_C_FLAGS='--std=gnu90 -Wall -Werror -Wextra -Wpedantic -pedantic-errors -Wdouble-promotion -Wformat-overflow=2 -Wformat-security -Wformat-signedness -Wformat-truncation=2 -Wformat-y2k -Wmissing-include-dirs -Wshift-overflow=2 -Wswitch-bool -Wno-unused-parameter -Wuninitialized -Wstrict-overflow=2 -Wstringop-overflow=4 -Wstringop-truncation -Wduplicated-branches -Wduplicated-cond -Wdeclaration-after-statement -Wshadow -Wunsafe-loop-optimizations -Wundef -Wcast-align -Wno-clobbered -Wjump-misses-init -Wno-sign-compare -Wlogical-op -Waggregate-return -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wno-long-long -Wdisabled-optimization -Wno-overlength-strings' \ + .. export NUMCPUS=`grep -c '^processor' /proc/cpuinfo` make -j$NUMCPUS --load-average=$NUMCPUS make test diff --git a/cdjpeg.c b/cdjpeg.c index 5278c1db..304a6650 100644 --- a/cdjpeg.c +++ b/cdjpeg.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2019, D. R. Commander. + * Copyright (C) 2019, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -34,7 +34,7 @@ progress_monitor(j_common_ptr cinfo) int scan_no = ((j_decompress_ptr)cinfo)->input_scan_number; if (scan_no > (int)prog->max_scans) { - fprintf(stderr, "Scan number %d exceeds maximum scans (%d)\n", scan_no, + fprintf(stderr, "Scan number %d exceeds maximum scans (%u)\n", scan_no, prog->max_scans); exit(EXIT_FAILURE); } diff --git a/djpeg.c b/djpeg.c index d02a2183..b30a5e43 100644 --- a/djpeg.c +++ b/djpeg.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2013-2019 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010-2011, 2013-2017, 2019-2020, D. R. Commander. + * Copyright (C) 2010-2011, 2013-2017, 2019-2020, 2022, D. R. Commander. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -717,7 +717,7 @@ main(int argc, char **argv) * that skip_start <= skip_end. */ if (skip_end > cinfo.output_height - 1) { - fprintf(stderr, "%s: skip region exceeds image height %d\n", progname, + fprintf(stderr, "%s: skip region exceeds image height %u\n", progname, cinfo.output_height); exit(EXIT_FAILURE); } @@ -738,7 +738,7 @@ main(int argc, char **argv) } if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) != skip_end - skip_start + 1) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n", + fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", progname, tmp, skip_end - skip_start + 1); exit(EXIT_FAILURE); } @@ -757,7 +757,7 @@ main(int argc, char **argv) */ if (crop_x + crop_width > cinfo.output_width || crop_y + crop_height > cinfo.output_height) { - fprintf(stderr, "%s: crop dimensions exceed image dimensions %d x %d\n", + fprintf(stderr, "%s: crop dimensions exceed image dimensions %u x %u\n", progname, cinfo.output_width, cinfo.output_height); exit(EXIT_FAILURE); } @@ -778,7 +778,7 @@ main(int argc, char **argv) /* Process data */ if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n", + fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", progname, tmp, crop_y); exit(EXIT_FAILURE); } @@ -791,7 +791,7 @@ main(int argc, char **argv) jpeg_skip_scanlines(&cinfo, cinfo.output_height - crop_y - crop_height)) != cinfo.output_height - crop_y - crop_height) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %d rather than %d\n", + fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", progname, tmp, cinfo.output_height - crop_y - crop_height); exit(EXIT_FAILURE); } diff --git a/rdjpgcom.c b/rdjpgcom.c index 76736d74..fc0c08c0 100644 --- a/rdjpgcom.c +++ b/rdjpgcom.c @@ -4,8 +4,8 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1997, Thomas G. Lane. * Modified 2009 by Bill Allombert, Guido Vollbeding. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -249,7 +249,7 @@ process_COM(int raw) } else if (isprint(ch)) { putc(ch, stdout); } else { - printf("\\%03o", ch); + printf("\\%03o", (unsigned int)ch); } lastch = ch; length--; diff --git a/rdppm.c b/rdppm.c index cd6f9a4e..439eefb6 100644 --- a/rdppm.c +++ b/rdppm.c @@ -181,13 +181,13 @@ get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), ptr[aindex] = 0xFF;) else - GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),) + GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), {}) } else { if (aindex >= 0) GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], ptr[aindex] = 0xFF;) else - GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],) + GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {}) } return 1; } @@ -255,13 +255,13 @@ get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), ptr[aindex] = 0xFF;) else - RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval),) + RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), {}) } else { if (aindex >= 0) RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], ptr[aindex] = 0xFF;) else - RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],) + RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {}) } return 1; } @@ -347,12 +347,12 @@ get_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) if (aindex >= 0) GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;) else - GRAY_RGB_READ_LOOP(*bufferptr++,) + GRAY_RGB_READ_LOOP(*bufferptr++, {}) } else { if (aindex >= 0) GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;) else - GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)],) + GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {}) } return 1; } @@ -415,12 +415,12 @@ get_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) if (aindex >= 0) RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;) else - RGB_READ_LOOP(*bufferptr++,) + RGB_READ_LOOP(*bufferptr++, {}) } else { if (aindex >= 0) RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;) else - RGB_READ_LOOP(rescale[UCH(*bufferptr++)],) + RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {}) } return 1; } diff --git a/turbojpeg.c b/turbojpeg.c index a6888a20..d780dc25 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -2010,13 +2010,13 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, for (ci = 0; ci < cinfo->num_components; ci++) { jpeg_component_info *compptr = &cinfo->comp_info[ci]; - tjregion arrayRegion = { - 0, 0, compptr->width_in_blocks * DCTSIZE, DCTSIZE - }; - tjregion planeRegion = { - 0, 0, compptr->width_in_blocks * DCTSIZE, - compptr->height_in_blocks * DCTSIZE - }; + tjregion arrayRegion = { 0, 0, 0, 0 }; + tjregion planeRegion = { 0, 0, 0, 0 }; + + arrayRegion.w = compptr->width_in_blocks * DCTSIZE; + arrayRegion.h = DCTSIZE; + planeRegion.w = compptr->width_in_blocks * DCTSIZE; + planeRegion.h = compptr->height_in_blocks * DCTSIZE; for (by = 0; by < compptr->height_in_blocks; by += compptr->v_samp_factor) { From da41ab94e7d0b9ce4fb4ccfd7f56c861933f7dfb Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 6 Jan 2022 12:57:26 -0600 Subject: [PATCH 39/56] GitHub Actions: Specify Catalina for macOS build macos-latest now maps to the Big Sur image, which doesn't have Xcode 12.2 installed. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da292845..9a5fd710 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,7 @@ jobs: run: | aws s3 sync --acl public-read --delete $HOME/src/ljt.nightly/latest/files/ s3://libjpeg-turbo-pr/${{env.BRANCH}}/${{github.job}}/ macos: - runs-on: macos-latest + runs-on: macos-10.15 steps: - name: Set global environment variables run: | From 14ce28a92d45e4e22b643bd845ba6c543ebcd388 Mon Sep 17 00:00:00 2001 From: DRC Date: Sat, 29 Jan 2022 12:33:40 -0600 Subject: [PATCH 40/56] TJBench: Remove innocuous always-true condition This was accidentally introduced into tjbench.c in 890f1e0413b54c40b663208779d4ea9dae20eaef and ported into the Java version from there. Based on https://github.com/libjpeg-turbo/libjpeg-turbo/pull/571/commits/4be6d4e7bdd09a73ee8456aa07693afa31ef2148 Refer to #571 --- java/TJBench.java | 2 +- tjbench.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/TJBench.java b/java/TJBench.java index 0fadab14..3a061d87 100644 --- a/java/TJBench.java +++ b/java/TJBench.java @@ -649,7 +649,7 @@ final class TJBench { sigFig((double)(w * h * ps) / (double)totalJpegSize, 4), quiet == 2 ? "\n" : " "); - } else if (quiet == 0) { + } else { System.out.format("Transform --> Frame rate: %f fps\n", 1.0 / elapsed); System.out.format(" Output image size: %d bytes\n", diff --git a/tjbench.c b/tjbench.c index 156c9061..4f5e1659 100644 --- a/tjbench.c +++ b/tjbench.c @@ -685,7 +685,7 @@ static int decompTest(char *fileName) sigfig((double)(w * h * ps) / (double)totalJpegSize, 4, tempStr2, 80), quiet == 2 ? "\n" : " "); - } else if (!quiet) { + } else { printf("Transform --> Frame rate: %f fps\n", 1.0 / elapsed); printf(" Output image size: %lu bytes\n", From d7d16df646d92cb55a69469c383363ffbca88e32 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 1 Feb 2022 09:11:19 -0600 Subject: [PATCH 41/56] Fix segv w/ h2v2 merged upsamp, jpeg_crop_scanline The h2v2 (4:2:0) merged upsampler uses a spare row buffer so that it can upsample two rows at a time but return only one row to the application, if necessary. merged_2v_upsample() copies from this spare row buffer into the application-supplied output buffer, using the out_row_width field in the my_merged_upsampler struct to determine how many samples to copy. out_row_width is set in jinit_merged_upsampler(), which is called within the body of jpeg_start_decompress(). Since jpeg_crop_scanline() must be called after jpeg_start_decompress(), jpeg_crop_scanline() must modify the value of out_row_width if the h2v2 merged upsampler will be used. Otherwise, merged_2v_upsample() can overflow the output buffer if the number of bytes between the current output buffer position and the end of the buffer is less than the number of bytes required to represent an uncropped scanline of the output image. All of the destination managers used by djpeg allocate either a whole image buffer or a scanline buffer based on the uncropped output image width, so this issue is not reproducible using djpeg. Fixes #574 --- ChangeLog.md | 8 ++++++++ jdapistd.c | 8 +++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6ceacd54..e92ccc48 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,14 @@ grayscale JPEG images if the input files contain only shades of gray. 3. The build system now enables the intrinsics implementation of the AArch64 (Arm 64-bit) Neon SIMD extensions by default when using GCC 12 or later. +4. Fixed a segfault that occurred while decompressing a 4:2:0 JPEG image using +the merged (non-fancy) upsampling algorithms (that is, with +`cinfo.do_fancy_upsampling` set to `FALSE`) along with `jpeg_crop_scanline()`. +Specifically, the segfault occurred if the number of bytes remaining in the +output buffer was less than the number of bytes required to represent one +uncropped scanline of the output image. For that reason, the issue could only +be reproduced using the libjpeg API, not using djpeg. + 2.1.2 ===== diff --git a/jdapistd.c b/jdapistd.c index 695a6200..8827d8ab 100644 --- a/jdapistd.c +++ b/jdapistd.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1996, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2015-2020, D. R. Commander. + * Copyright (C) 2010, 2015-2020, 2022, D. R. Commander. * Copyright (C) 2015, Google, Inc. * For conditions of distribution and use, see the accompanying README.ijg * file. @@ -159,6 +159,7 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, JDIMENSION input_xoffset; boolean reinit_upsampler = FALSE; jpeg_component_info *compptr; + my_master_ptr master = (my_master_ptr)cinfo->master; if (cinfo->global_state != DSTATE_SCANNING || cinfo->output_scanline != 0) ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); @@ -208,6 +209,11 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, */ *width = *width + input_xoffset - *xoffset; cinfo->output_width = *width; + if (master->using_merged_upsample && cinfo->max_v_samp_factor == 2) { + my_merged_upsample_ptr upsample = (my_merged_upsample_ptr)cinfo->upsample; + upsample->out_row_width = + cinfo->output_width * cinfo->out_color_components; + } /* Set the first and last iMCU columns that we must decompress. These values * will be used in single-scan decompressions. From a3d4aadd0d1597ad46edcbe3b964499ec785d40c Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 1 Feb 2022 12:53:28 -0600 Subject: [PATCH 42/56] Build: Embed version/API/(C) info in MSVC DLLs Based on: https://github.com/TheDorkKnight/libjpeg-turbo/commit/da7a18801a5c305d3f8a71b065f179f1e22b73ae Closes #576 --- CMakeLists.txt | 13 +++++++++++- cmakescripts/BuildPackages.cmake | 12 ----------- cmakescripts/PackageInfo.cmake | 13 ++++++++++++ jversion.h => jversion.h.in | 2 +- sharedlib/CMakeLists.txt | 5 +++++ win/jpeg.rc.in | 35 ++++++++++++++++++++++++++++++++ win/turbojpeg.rc.in | 35 ++++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 14 deletions(-) create mode 100644 cmakescripts/PackageInfo.cmake rename jversion.h => jversion.h.in (95%) create mode 100644 win/jpeg.rc.in create mode 100644 win/turbojpeg.rc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index bb6efcf4..639ea570 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ endif() project(libjpeg-turbo C) set(VERSION 2.1.3) +set(COPYRIGHT_YEAR "1991-2022") string(REPLACE "." ";" VERSION_TRIPLET ${VERSION}) list(GET VERSION_TRIPLET 0 VERSION_MAJOR) list(GET VERSION_TRIPLET 1 VERSION_MINOR) @@ -52,6 +53,8 @@ message(STATUS "CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}") message(STATUS "VERSION = ${VERSION}, BUILD = ${BUILD}") +include(cmakescripts/PackageInfo.cmake) + # Detect CPU type and whether we're building 64-bit or 32-bit code math(EXPR BITS "${CMAKE_SIZEOF_VOID_P} * 8") string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR_LC) @@ -336,7 +339,8 @@ message(STATUS "libjpeg API shared library version = ${SO_MAJOR_VERSION}.${SO_AG # minor SO versions don't change. However, we increase the middle number (the # SO "age") whenever functions are added to the API. set(TURBOJPEG_SO_MAJOR_VERSION 0) -set(TURBOJPEG_SO_VERSION 0.2.0) +set(TURBOJPEG_SO_AGE 2) +set(TURBOJPEG_SO_VERSION 0.${TURBOJPEG_SO_AGE}.0) ############################################################################### @@ -516,6 +520,7 @@ else() configure_file(jconfig.h.in jconfig.h) endif() configure_file(jconfigint.h.in jconfigint.h) +configure_file(jversion.h.in jversion.h) if(UNIX) configure_file(libjpeg.map.in libjpeg.map) endif() @@ -600,6 +605,12 @@ if(WITH_TURBOJPEG) include_directories(${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) set(TJMAPFILE ${CMAKE_CURRENT_SOURCE_DIR}/turbojpeg-mapfile.jni) endif() + if(MSVC) + configure_file(${CMAKE_SOURCE_DIR}/win/turbojpeg.rc.in + ${CMAKE_BINARY_DIR}/win/turbojpeg.rc) + set(TURBOJPEG_SOURCES ${TURBOJPEG_SOURCES} + ${CMAKE_BINARY_DIR}/win/turbojpeg.rc) + endif() add_library(turbojpeg SHARED ${TURBOJPEG_SOURCES}) set_property(TARGET turbojpeg PROPERTY COMPILE_FLAGS "-DBMP_SUPPORTED -DPPM_SUPPORTED") diff --git a/cmakescripts/BuildPackages.cmake b/cmakescripts/BuildPackages.cmake index 37356a2c..cfbb2c8a 100644 --- a/cmakescripts/BuildPackages.cmake +++ b/cmakescripts/BuildPackages.cmake @@ -1,18 +1,6 @@ # This file is included from the top-level CMakeLists.txt. We just store it # here to avoid cluttering up that file. -set(PKGNAME ${CMAKE_PROJECT_NAME} CACHE STRING - "Distribution package name (default: ${CMAKE_PROJECT_NAME})") -set(PKGVENDOR "The ${CMAKE_PROJECT_NAME} Project" CACHE STRING - "Vendor name to be included in distribution package descriptions (default: The ${CMAKE_PROJECT_NAME} Project)") -set(PKGURL "http://www.${CMAKE_PROJECT_NAME}.org" CACHE STRING - "URL of project web site to be included in distribution package descriptions (default: http://www.${CMAKE_PROJECT_NAME}.org)") -set(PKGEMAIL "information@${CMAKE_PROJECT_NAME}.org" CACHE STRING - "E-mail of project maintainer to be included in distribution package descriptions (default: information@${CMAKE_PROJECT_NAME}.org") -set(PKGID "com.${CMAKE_PROJECT_NAME}.${PKGNAME}" CACHE STRING - "Globally unique package identifier (reverse DNS notation) (default: com.${CMAKE_PROJECT_NAME}.${PKGNAME})") - - ############################################################################### # Linux RPM and DEB ############################################################################### diff --git a/cmakescripts/PackageInfo.cmake b/cmakescripts/PackageInfo.cmake new file mode 100644 index 00000000..36f6133a --- /dev/null +++ b/cmakescripts/PackageInfo.cmake @@ -0,0 +1,13 @@ +# This file is included from the top-level CMakeLists.txt. We just store it +# here to avoid cluttering up that file. + +set(PKGNAME ${CMAKE_PROJECT_NAME} CACHE STRING + "Distribution package name (default: ${CMAKE_PROJECT_NAME})") +set(PKGVENDOR "The ${CMAKE_PROJECT_NAME} Project" CACHE STRING + "Vendor name to be included in distribution package descriptions (default: The ${CMAKE_PROJECT_NAME} Project)") +set(PKGURL "http://www.${CMAKE_PROJECT_NAME}.org" CACHE STRING + "URL of project web site to be included in distribution package descriptions (default: http://www.${CMAKE_PROJECT_NAME}.org)") +set(PKGEMAIL "information@${CMAKE_PROJECT_NAME}.org" CACHE STRING + "E-mail of project maintainer to be included in distribution package descriptions (default: information@${CMAKE_PROJECT_NAME}.org") +set(PKGID "com.${CMAKE_PROJECT_NAME}.${PKGNAME}" CACHE STRING + "Globally unique package identifier (reverse DNS notation) (default: com.${CMAKE_PROJECT_NAME}.${PKGNAME})") diff --git a/jversion.h b/jversion.h.in similarity index 95% rename from jversion.h rename to jversion.h.in index 63db95b9..dca4f08f 100644 --- a/jversion.h +++ b/jversion.h.in @@ -51,4 +51,4 @@ "Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding" #define JCOPYRIGHT_SHORT \ - "Copyright (C) 1991-2022 The libjpeg-turbo Project and many others" + "Copyright (C) @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others" diff --git a/sharedlib/CMakeLists.txt b/sharedlib/CMakeLists.txt index 78a2f28b..aea0b9d7 100644 --- a/sharedlib/CMakeLists.txt +++ b/sharedlib/CMakeLists.txt @@ -35,6 +35,11 @@ if(WIN32) set(DEFFILE ../win/jpeg${SO_MAJOR_VERSION}.def) endif() endif() +if(MSVC) + configure_file(${CMAKE_SOURCE_DIR}/win/jpeg.rc.in + ${CMAKE_BINARY_DIR}/win/jpeg.rc) + set(JPEG_SRCS ${JPEG_SRCS} ${CMAKE_BINARY_DIR}/win/jpeg.rc) +endif() add_library(jpeg SHARED ${JPEG_SRCS} ${DEFFILE} $ ${SIMD_OBJS}) diff --git a/win/jpeg.rc.in b/win/jpeg.rc.in new file mode 100644 index 00000000..fca72b7f --- /dev/null +++ b/win/jpeg.rc.in @@ -0,0 +1,35 @@ +#include "Winver.h" +#include "winres.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @SO_MAJOR_VERSION@,@SO_AGE@,@SO_MINOR_VERSION@,0 + PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,0 + FILEFLAGSMASK 0x17L +#ifndef NDEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "@PKGVENDOR@" + VALUE "FileDescription", "libjpeg API DLL" + VALUE "FileVersion", "@SO_MAJOR_VERSION@,@SO_AGE@,@SO_MINOR_VERSION@,0" + VALUE "ProductVersion", "@VERSION@" + VALUE "ProductName", "@CMAKE_PROJECT_NAME@" + VALUE "InternalName", "jpeg@SO_MAJOR_VERSION@" + VALUE "LegalCopyright", "Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others" + VALUE "OriginalFilename", "jpeg@SO_MAJOR_VERSION@.dll" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/win/turbojpeg.rc.in b/win/turbojpeg.rc.in new file mode 100644 index 00000000..cc7ab3a7 --- /dev/null +++ b/win/turbojpeg.rc.in @@ -0,0 +1,35 @@ +#include "Winver.h" +#include "winres.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,@TURBOJPEG_SO_AGE@,0,0 + PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,0 + FILEFLAGSMASK 0x17L +#ifndef NDEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "@PKGVENDOR@" + VALUE "FileDescription", "TurboJPEG API DLL" + VALUE "FileVersion", "0,@TURBOJPEG_SO_AGE@,0,0" + VALUE "ProductVersion", "@VERSION@" + VALUE "ProductName", "@CMAKE_PROJECT_NAME@" + VALUE "InternalName", "turbojpeg" + VALUE "LegalCopyright", "Copyright \xA9 @COPYRIGHT_YEAR@ The libjpeg-turbo Project and many others" + VALUE "OriginalFilename", "turbojpeg.dll" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END From b579fc114dee195df8408144121353abf424288d Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 7 Feb 2022 15:27:50 -0600 Subject: [PATCH 43/56] Eliminate unnecessary JFREAD()/JFWRITE() macros --- djpeg.c | 2 +- jdatadst.c | 4 ++-- jdatasrc.c | 4 ++-- jinclude.h | 11 ----------- rdbmp.c | 2 +- rdgif.c | 4 ++-- rdppm.c | 2 +- rdtarga.c | 4 ++-- wrbmp.c | 14 +++++++------- wrgif.c | 4 ++-- wrppm.c | 12 ++++++------ wrtarga.c | 8 ++++---- 12 files changed, 30 insertions(+), 41 deletions(-) diff --git a/djpeg.c b/djpeg.c index b30a5e43..dfd6d900 100644 --- a/djpeg.c +++ b/djpeg.c @@ -647,7 +647,7 @@ main(int argc, char **argv) fprintf(stderr, "%s: memory allocation failure\n", progname); exit(EXIT_FAILURE); } - nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE); + nbytes = fread(&inbuffer[insize], 1, INPUT_BUF_SIZE, input_file); if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) { if (file_index < argc) fprintf(stderr, "%s: can't read from %s\n", progname, diff --git a/jdatadst.c b/jdatadst.c index fe8c0543..6b4fed23 100644 --- a/jdatadst.c +++ b/jdatadst.c @@ -111,7 +111,7 @@ empty_output_buffer(j_compress_ptr cinfo) { my_dest_ptr dest = (my_dest_ptr)cinfo->dest; - if (JFWRITE(dest->outfile, dest->buffer, OUTPUT_BUF_SIZE) != + if (fwrite(dest->buffer, 1, OUTPUT_BUF_SIZE, dest->outfile) != (size_t)OUTPUT_BUF_SIZE) ERREXIT(cinfo, JERR_FILE_WRITE); @@ -170,7 +170,7 @@ term_destination(j_compress_ptr cinfo) /* Write any data remaining in the buffer */ if (datacount > 0) { - if (JFWRITE(dest->outfile, dest->buffer, datacount) != datacount) + if (fwrite(dest->buffer, 1, datacount, dest->outfile) != datacount) ERREXIT(cinfo, JERR_FILE_WRITE); } fflush(dest->outfile); diff --git a/jdatasrc.c b/jdatasrc.c index eadb4a2c..e36a30d8 100644 --- a/jdatasrc.c +++ b/jdatasrc.c @@ -5,7 +5,7 @@ * Copyright (C) 1994-1996, Thomas G. Lane. * Modified 2009-2011 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2013, 2016, D. R. Commander. + * Copyright (C) 2013, 2016, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -104,7 +104,7 @@ fill_input_buffer(j_decompress_ptr cinfo) my_src_ptr src = (my_src_ptr)cinfo->src; size_t nbytes; - nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); + nbytes = fread(src->buffer, 1, INPUT_BUF_SIZE, src->infile); if (nbytes <= 0) { if (src->start_of_file) /* Treat empty input file as fatal error */ diff --git a/jinclude.h b/jinclude.h index 23248767..6ed982d3 100644 --- a/jinclude.h +++ b/jinclude.h @@ -34,14 +34,3 @@ #include #include #include - -/* - * The modules that use fread() and fwrite() always invoke them through - * these macros. On some systems you may need to twiddle the argument casts. - * CAUTION: argument order is different from underlying functions! - */ - -#define JFREAD(file, buf, sizeofbuf) \ - ((size_t)fread((void *)(buf), (size_t)1, (size_t)(sizeofbuf), (file))) -#define JFWRITE(file, buf, sizeofbuf) \ - ((size_t)fwrite((const void *)(buf), (size_t)1, (size_t)(sizeofbuf), (file))) diff --git a/rdbmp.c b/rdbmp.c index 0124f4d2..433ebe2e 100644 --- a/rdbmp.c +++ b/rdbmp.c @@ -39,7 +39,7 @@ typedef unsigned char U_CHAR; #define ReadOK(file, buffer, len) \ - (JFREAD(file, buffer, len) == ((size_t)(len))) + (fread(buffer, 1, len, file) == ((size_t)(len))) static int alpha_index[JPEG_NUMCS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1 diff --git a/rdgif.c b/rdgif.c index 36f0929f..bdf74012 100644 --- a/rdgif.c +++ b/rdgif.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1997, Thomas G. Lane. * Modified 2019 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2021, D. R. Commander. + * Copyright (C) 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -45,7 +45,7 @@ typedef unsigned char U_CHAR; #define ReadOK(file, buffer, len) \ - (JFREAD(file, buffer, len) == ((size_t)(len))) + (fread(buffer, 1, len, file) == ((size_t)(len))) #define MAXCOLORMAPSIZE 256 /* max # of colors in a GIF colormap */ diff --git a/rdppm.c b/rdppm.c index 439eefb6..409497d6 100644 --- a/rdppm.c +++ b/rdppm.c @@ -48,7 +48,7 @@ typedef unsigned char U_CHAR; #define ReadOK(file, buffer, len) \ - (JFREAD(file, buffer, len) == ((size_t)(len))) + (fread(buffer, 1, len, file) == ((size_t)(len))) static int alpha_index[JPEG_NUMCS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1 diff --git a/rdtarga.c b/rdtarga.c index 8f2d0316..3ed7eb34 100644 --- a/rdtarga.c +++ b/rdtarga.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1996, Thomas G. Lane. * Modified 2017 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2018, 2021, D. R. Commander. + * Copyright (C) 2018, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -33,7 +33,7 @@ typedef unsigned char U_CHAR; #define ReadOK(file, buffer, len) \ - (JFREAD(file, buffer, len) == ((size_t)(len))) + (fread(buffer, 1, len, file) == ((size_t)(len))) /* Private version of data source object */ diff --git a/wrbmp.c b/wrbmp.c index 56a53a44..45fff684 100644 --- a/wrbmp.c +++ b/wrbmp.c @@ -165,7 +165,7 @@ put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, *outptr++ = 0; if (!dest->use_inversion_array) - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width); + fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file); } METHODDEF(void) @@ -200,7 +200,7 @@ put_gray_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, *outptr++ = 0; if (!dest->use_inversion_array) - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->row_width); + fwrite(dest->iobuffer, 1, dest->row_width, dest->pub.output_file); } @@ -281,9 +281,9 @@ write_bmp_header(j_decompress_ptr cinfo, bmp_dest_ptr dest) PUT_2B(bmpinfoheader, 32, cmap_entries); /* biClrUsed */ /* we leave biClrImportant = 0 */ - if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t)14) + if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14) ERREXIT(cinfo, JERR_FILE_WRITE); - if (JFWRITE(dest->pub.output_file, bmpinfoheader, 40) != (size_t)40) + if (fwrite(bmpinfoheader, 1, 40, dest->pub.output_file) != (size_t)40) ERREXIT(cinfo, JERR_FILE_WRITE); if (cmap_entries > 0) @@ -342,9 +342,9 @@ write_os2_header(j_decompress_ptr cinfo, bmp_dest_ptr dest) PUT_2B(bmpcoreheader, 8, 1); /* bcPlanes - must be 1 */ PUT_2B(bmpcoreheader, 10, bits_per_pixel); /* bcBitCount */ - if (JFWRITE(dest->pub.output_file, bmpfileheader, 14) != (size_t)14) + if (fwrite(bmpfileheader, 1, 14, dest->pub.output_file) != (size_t)14) ERREXIT(cinfo, JERR_FILE_WRITE); - if (JFWRITE(dest->pub.output_file, bmpcoreheader, 12) != (size_t)12) + if (fwrite(bmpcoreheader, 1, 12, dest->pub.output_file) != (size_t)12) ERREXIT(cinfo, JERR_FILE_WRITE); if (cmap_entries > 0) @@ -456,7 +456,7 @@ finish_output_bmp(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo) ((j_common_ptr)cinfo, dest->whole_image, row - 1, (JDIMENSION)1, FALSE); data_ptr = image_ptr[0]; - (void)JFWRITE(outfile, data_ptr, dest->row_width); + fwrite(data_ptr, 1, dest->row_width, outfile); } if (progress != NULL) progress->completed_extra_passes++; diff --git a/wrgif.c b/wrgif.c index bac672c6..620a3ba9 100644 --- a/wrgif.c +++ b/wrgif.c @@ -114,8 +114,8 @@ flush_packet(gif_dest_ptr dinfo) { if (dinfo->bytesinpkt > 0) { /* never write zero-length packet */ dinfo->packetbuf[0] = (char)dinfo->bytesinpkt++; - if (JFWRITE(dinfo->pub.output_file, dinfo->packetbuf, dinfo->bytesinpkt) != - (size_t)dinfo->bytesinpkt) + if (fwrite(dinfo->packetbuf, 1, dinfo->bytesinpkt, + dinfo->pub.output_file) != (size_t)dinfo->bytesinpkt) ERREXIT(dinfo->cinfo, JERR_FILE_WRITE); dinfo->bytesinpkt = 0; } diff --git a/wrppm.c b/wrppm.c index ffa4f89e..57c8aaff 100644 --- a/wrppm.c +++ b/wrppm.c @@ -92,7 +92,7 @@ put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, { ppm_dest_ptr dest = (ppm_dest_ptr)dinfo; - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -121,7 +121,7 @@ copy_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, PUTPPMSAMPLE(bufferptr, *ptr++); } #endif - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -149,7 +149,7 @@ put_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, JDIMENSION rows_supplied) PUTPPMSAMPLE(bufferptr, ptr[bindex]); ptr += ps; } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -175,7 +175,7 @@ put_cmyk(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, PUTPPMSAMPLE(bufferptr, g); PUTPPMSAMPLE(bufferptr, b); } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -205,7 +205,7 @@ put_demapped_rgb(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, PUTPPMSAMPLE(bufferptr, color_map1[pixval]); PUTPPMSAMPLE(bufferptr, color_map2[pixval]); } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -224,7 +224,7 @@ put_demapped_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, for (col = cinfo->output_width; col > 0; col--) { PUTPPMSAMPLE(bufferptr, color_map[*ptr++]); } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } diff --git a/wrtarga.c b/wrtarga.c index 57c6a2ff..67ca1f00 100644 --- a/wrtarga.c +++ b/wrtarga.c @@ -79,7 +79,7 @@ write_header(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, int num_colors) } } - if (JFWRITE(dinfo->output_file, targaheader, 18) != (size_t)18) + if (fwrite(targaheader, 1, 18, dinfo->output_file) != (size_t)18) ERREXIT(cinfo, JERR_FILE_WRITE); } @@ -107,7 +107,7 @@ put_pixel_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, outptr[2] = inptr[0]; inptr += 3, outptr += 3; } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } METHODDEF(void) @@ -122,7 +122,7 @@ put_gray_rows(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, inptr = dest->pub.buffer[0]; outptr = dest->iobuffer; memcpy(outptr, inptr, cinfo->output_width); - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } @@ -146,7 +146,7 @@ put_demapped_gray(j_decompress_ptr cinfo, djpeg_dest_ptr dinfo, for (col = cinfo->output_width; col > 0; col--) { *outptr++ = color_map0[*inptr++]; } - (void)JFWRITE(dest->pub.output_file, dest->iobuffer, dest->buffer_width); + fwrite(dest->iobuffer, 1, dest->buffer_width, dest->pub.output_file); } From 548490fe5e2aa31cb00f6602d5a478b068b99682 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 10 Feb 2022 11:37:06 -0600 Subject: [PATCH 44/56] Ensure that strncpy() dest strings are terminated - Since the ERREXITS() and TRACEMSS() macros are never used internally (they are a relic of the legacy memory managers that libjpeg provided), the only risk was that an external program might have invoked one of those macros with a string longer than 79 characters (JMSG_STR_PARM_MAX - 1). - TJBench never invokes the THROW_TJ() macro with a string longer than 199 (JMSG_LENGTH_MAX - 1) characters, so there was no risk. However, it's a good idea to explicitly terminate the destination strings so that anyone looking at the code can immediately tell that it is safe. --- jerror.h | 4 +++- tjbench.c | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/jerror.h b/jerror.h index 133fd3f1..eb44a114 100644 --- a/jerror.h +++ b/jerror.h @@ -5,7 +5,7 @@ * Copyright (C) 1994-1997, Thomas G. Lane. * Modified 1997-2009 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2014, 2017, 2021, D. R. Commander. + * Copyright (C) 2014, 2017, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -268,6 +268,7 @@ JMESSAGE(JERR_BAD_DROP_SAMPLING, #define ERREXITS(cinfo, code, str) \ ((cinfo)->err->msg_code = (code), \ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \ (*(cinfo)->err->error_exit) ((j_common_ptr)(cinfo))) #define MAKESTMT(stuff) do { stuff } while (0) @@ -324,6 +325,7 @@ JMESSAGE(JERR_BAD_DROP_SAMPLING, #define TRACEMSS(cinfo, lvl, code, str) \ ((cinfo)->err->msg_code = (code), \ strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (cinfo)->err->msg_parm.s[JMSG_STR_PARM_MAX - 1] = '\0', \ (*(cinfo)->err->emit_message) ((j_common_ptr)(cinfo), (lvl))) #endif /* JERROR_H */ diff --git a/tjbench.c b/tjbench.c index 4f5e1659..344cb4cb 100644 --- a/tjbench.c +++ b/tjbench.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2009-2019, 2021 D. R. Commander. All Rights Reserved. + * Copyright (C)2009-2019, 2021-2022 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: @@ -61,8 +61,10 @@ int tjErrorLine = -1, tjErrorCode = -1; if (strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \ strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \ tjErrorCode != _tjErrorCode || tjErrorLine != __LINE__) { \ - strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX - 1); \ - strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX - 1); \ + strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \ + tjErrorStr[JMSG_LENGTH_MAX - 1] = '\0'; \ + strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX); \ + tjErrorMsg[JMSG_LENGTH_MAX - 1] = '\0'; \ tjErrorCode = _tjErrorCode; \ tjErrorLine = __LINE__; \ printf("WARNING in line %d while %s:\n%s\n", __LINE__, m, _tjErrorStr); \ From e1588a2a7bc01daa48b200576a35c8348577f212 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 10 Feb 2022 22:23:26 -0600 Subject: [PATCH 45/56] Build: Fix Neon capability detection w/ MSVC (broken by 57ba02a408a9a55ccff25aae8b164632a3a4f177) Refer to #547 --- simd/CMakeLists.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index 8606174e..ced8a124 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -258,28 +258,30 @@ endif() check_c_source_compiles(" #include int main(int argc, char **argv) { - const int16_t input[] = { + int16_t input[] = { (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc, (int16_t)argc }; int16x4x3_t output = vld1_s16_x3(input); - return (int)output.val[0][0]; + vst3_s16(input, output); + return (int)input[0]; }" HAVE_VLD1_S16_X3) check_c_source_compiles(" #include int main(int argc, char **argv) { - const uint16_t input[] = { + uint16_t input[] = { (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc, (uint16_t)argc }; uint16x4x2_t output = vld1_u16_x2(input); - return (int)output.val[0][0]; + vst2_u16(input, output); + return (int)input[0]; }" HAVE_VLD1_U16_X2) check_c_source_compiles(" #include int main(int argc, char **argv) { - const uint8_t input[] = { + uint8_t input[] = { (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, @@ -298,7 +300,8 @@ check_c_source_compiles(" (uint8_t)argc, (uint8_t)argc, (uint8_t)argc, (uint8_t)argc }; uint8x16x4_t output = vld1q_u8_x4(input); - return (int)output.val[0][0]; + vst4q_u8(input, output); + return (int)input[0]; }" HAVE_VLD1Q_U8_X4) if(BITS EQUAL 32) unset(CMAKE_REQUIRED_FLAGS) From 6d2d6d3baf562d83101e22d3673ab1d539ed58e8 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 11 Feb 2022 09:34:01 -0600 Subject: [PATCH 46/56] "YASM" = "Yasm" The assembler name was initially spelled "YASM", but it has been "Yasm" for the entirety of libjpeg-turbo's existence. --- BUILDING.md | 10 +++++----- ChangeLog.md | 8 ++++---- simd/CMakeLists.txt | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index f91abcd4..c1092730 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -10,18 +10,18 @@ Build Requirements - [CMake](http://www.cmake.org) v2.8.12 or later -- [NASM](http://www.nasm.us) or [YASM](http://yasm.tortall.net) +- [NASM](http://www.nasm.us) or [Yasm](http://yasm.tortall.net) (if building x86 or x86-64 SIMD extensions) * If using NASM, 2.13 or later is required. - * If using YASM, 1.2.0 or later is required. - * If building on macOS, NASM or YASM can be obtained from + * If using Yasm, 1.2.0 or later is required. + * If building on macOS, NASM or Yasm can be obtained from [MacPorts](http://www.macports.org/) or [Homebrew](http://brew.sh/). - NOTE: Currently, if it is desirable to hide the SIMD function symbols in Mac executables or shared libraries that statically link with - libjpeg-turbo, then NASM 2.14 or later or YASM must be used when + libjpeg-turbo, then NASM 2.14 or later or Yasm must be used when building libjpeg-turbo. * If building on Windows, **nasm.exe**/**yasm.exe** should be in your `PATH`. - * NASM and YASM are located in the CRB (Code Ready Builder) repository on + * NASM and Yasm are located in the CRB (Code Ready Builder) repository on Red Hat Enterprise Linux 8 and in the PowerTools repository on CentOS 8, which is not enabled by default. diff --git a/ChangeLog.md b/ChangeLog.md index e92ccc48..e6700c3c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -665,7 +665,7 @@ algorithm that caused incorrect dithering in the output image. This algorithm now produces bitwise-identical results to the unmerged algorithms. 12. The SIMD function symbols for x86[-64]/ELF, MIPS/ELF, macOS/x86[-64] (if -libjpeg-turbo is built with YASM), and iOS/Arm[64] builds are now private. +libjpeg-turbo is built with Yasm), and iOS/Arm[64] builds are now private. This prevents those symbols from being exposed in applications or shared libraries that link statically with libjpeg-turbo. @@ -1550,8 +1550,8 @@ either the fast or the accurate DCT/IDCT algorithms in the underlying codec. ### Significant changes relative to 1.2 beta1: -1. Fixed build issue with YASM on Unix systems (the libjpeg-turbo build system -was not adding the current directory to the assembler include path, so YASM +1. Fixed build issue with Yasm on Unix systems (the libjpeg-turbo build system +was not adding the current directory to the assembler include path, so Yasm was not able to find jsimdcfg.inc.) 2. Fixed out-of-bounds read in SSE2 SIMD code that occurred when decompressing @@ -1619,7 +1619,7 @@ transposed or rotated 90 degrees. 8. All legacy VirtualGL code has been re-factored, and this has allowed libjpeg-turbo, in its entirety, to be re-licensed under a BSD-style license. -9. libjpeg-turbo can now be built with YASM. +9. libjpeg-turbo can now be built with Yasm. 10. Added SIMD acceleration for ARM Linux and iOS platforms that support NEON instructions. diff --git a/simd/CMakeLists.txt b/simd/CMakeLists.txt index ced8a124..8521e42b 100644 --- a/simd/CMakeLists.txt +++ b/simd/CMakeLists.txt @@ -21,7 +21,7 @@ set(CMAKE_ASM_NASM_FLAGS_RELWITHDEBINFO_INIT "-g") # environment variable. This should happen automatically, but unfortunately # enable_language(ASM_NASM) doesn't parse the ASM_NASM environment variable # until after CMAKE_ASM_NASM_COMPILER has been populated with the results of -# searching for NASM or YASM in the PATH. +# searching for NASM or Yasm in the PATH. if(NOT DEFINED CMAKE_ASM_NASM_COMPILER AND DEFINED ENV{ASM_NASM}) set(CMAKE_ASM_NASM_COMPILER $ENV{ASM_NASM}) endif() From 6441ad0f83ee80eb1211d1146bf6af85b277049e Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 11 Feb 2022 09:56:41 -0600 Subject: [PATCH 47/56] BUILDING.md: Document NASM/Yasm path variables This was an oversight from the CMake build system overhaul in libjpeg-turbo 2.0 (6abd39160c5a3762e9ebe024e75407665093e715). Closes #580 --- BUILDING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/BUILDING.md b/BUILDING.md index c1092730..b1ddbe65 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -20,7 +20,11 @@ Build Requirements Mac executables or shared libraries that statically link with libjpeg-turbo, then NASM 2.14 or later or Yasm must be used when building libjpeg-turbo. - * If building on Windows, **nasm.exe**/**yasm.exe** should be in your `PATH`. + * If NASM or Yasm is not in your `PATH`, then you can specify the full path + to the assembler by using either the `CMAKE_ASM_NASM_COMPILER` CMake + variable or the `ASM_NASM` environment variable. On Windows, use forward + slashes rather than backslashes in the path (for example, + **c:/nasm/nasm.exe**). * NASM and Yasm are located in the CRB (Code Ready Builder) repository on Red Hat Enterprise Linux 8 and in the PowerTools repository on CentOS 8, which is not enabled by default. From 3ccb6ead239aa790f69f34767e0b4f5609c7b728 Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 11 Feb 2022 10:05:18 -0600 Subject: [PATCH 48/56] BUILDING.md: Remove NASM RPM rebuild instructions All currently supported Linux platforms now provide a recent enough version of either NASM or Yasm. --- BUILDING.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index b1ddbe65..4cbe3c06 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -29,21 +29,6 @@ Build Requirements Red Hat Enterprise Linux 8 and in the PowerTools repository on CentOS 8, which is not enabled by default. - The binary RPMs released by the NASM project do not work on older Linux - systems, such as Red Hat Enterprise Linux 5. On such systems, you can easily - build and install NASM from a source RPM by downloading one of the SRPMs from - - - - and executing the following as root: - - ARCH=`uname -m` - rpmbuild --rebuild nasm-{version}.src.rpm - rpm -Uvh /usr/src/redhat/RPMS/$ARCH/nasm-{version}.$ARCH.rpm - - NOTE: the NASM build will fail if texinfo is not installed. - - ### Un*x Platforms (including Linux, Mac, FreeBSD, Solaris, and Cygwin) - GCC v4.1 (or later) or Clang recommended for best performance From ab6cae6f3bfb06632364d6a807ff956d5f42da79 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 22 Feb 2022 10:23:19 -0600 Subject: [PATCH 49/56] BUILDING.md: Clarify that Ninja works with Windows --- BUILDING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 4cbe3c06..e682769e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -95,8 +95,9 @@ directory. For in-tree builds, these directories are the same. Ninja ----- -In all of the procedures and recipes below, replace `make` with `ninja` and -`Unix Makefiles` with `Ninja` if using Ninja. +If using Ninja, then replace `make` or `nmake` with `ninja`, and replace the +CMake generator (specified with the `-G` option) with `Ninja`, in all of the +procedures and recipes below. Build Procedure From 607b668ff96e40fdc749de9b1bb98e7f40c86d93 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 10 Feb 2022 11:33:49 -0600 Subject: [PATCH 50/56] MSVC: Eliminate C4996 warnings in API libs The primary purpose of this is to encourage adoption of libjpeg-turbo in downstream Windows projects that forbid the use of "deprecated" functions. libjpeg-turbo's usage of those functions was not actually unsafe, because: - libjpeg-turbo always checks the return value of fopen() and ensures that a NULL filename can never be passed to it. - libjpeg-turbo always checks the return value of getenv() and never passes a NULL argument to it. - The sprintf() calls in format_message() (jerror.c) could never overflow the destination string buffer or leave it unterminated as long as the buffer was at least JMSG_LENGTH_MAX bytes in length, as instructed. (Regardless, this commit replaces those calls with snprintf() calls.) - libjpeg-turbo never uses sscanf() to read strings or multi-byte character arrays. - Because of b7d6e84d6a9283dc2bc50ef9fcaadc0cdeb25c9f, wrjpgcom explicitly checks the bounds of the source and destination strings before calling strcat() and strcpy(). - libjpeg-turbo always ensures that the destination string is terminated when using strncpy(). (548490fe5e2aa31cb00f6602d5a478b068b99682 made this explicit.) Regarding thread safety: Technically speaking, getenv() is not thread-safe, because the returned pointer may be invalidated if another thread sets the same environment variable between the time that the first thread calls getenv() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if: (1) A multithreaded calling application used the deprecated and undocumented TJFLAG_FORCEMMX/TJFLAG_FORCESSE/TJFLAG_FORCESSE2 flags in the TurboJPEG API or set one of the corresponding environment variables (which are only intended for testing purposes.) Since the TurboJPEG API library only ever passed string constants to putenv(), the only inherent risk (i.e. the only risk introduced by the library and not the calling application) was that the SIMD extensions may have read an incorrect value from one of the aforementioned environment variables. or (2) A multithreaded calling application modified the value of the JPEGMEM environment variable in one thread while another thread was reading the value of that environment variable (in the body of jpeg_create_compress() or jpeg_create_decompress().) Given that the libjpeg API provides a thread-safe way for applications to modify the default memory limit without using the JPEGMEM environment variable, direct modification of that environment variable by calling applications is not supported. Microsoft's implementation of getenv_s() does not claim to be thread-safe either, so this commit uses getenv_s() solely to mollify Visual Studio. New inline functions and macros (GETENV_S() and PUTENV_S) wrap getenv_s()/_putenv_s() when building for Visual Studio and getenv()/setenv() otherwise, but GETENV_S()/PUTENV_S() provide no advantages over getenv()/setenv() other than parameter validation. They are implemented solely for convenience. Technically speaking, strerror() is not thread-safe, because the returned pointer may be invalidated if another thread changes the locale and/or calls strerror() between the time that the first thread calls strerror() and the time that that thread uses the return value. In practice, however, this could only occur with libjpeg-turbo if a multithreaded calling application encountered a file I/O error in tjLoadImage() or tjSaveImage(). Since both of those functions immediately copy the string returned from strerror() into a thread-local buffer, the risk is minimal, and the worst case would involve an incorrect error string being reported to the calling application. Regardless, this commit uses strerror_s() in the TurboJPEG API library when building for Visual Studio. Note that strerror_r() could have been used on Un*x systems, but it would have been necessary to handle both the POSIX and GNU implementations of that function and perform widespread compatibility testing. Such is left as an exercise for another day. Fixes #568 --- CMakeLists.txt | 4 +- cjpeg.c | 6 +- djpeg.c | 4 + jerror.c | 16 ++-- jinclude.h | 101 +++++++++++++++++++++++- jmemmgr.c | 10 ++- jpegtran.c | 6 +- md5/md5hl.c | 6 +- rdjpgcom.c | 4 + rdswitch.c | 4 + simd/arm/aarch32/jsimd.c | 13 ++- simd/arm/aarch64/jsimd.c | 23 +++--- simd/i386/jsimd.c | 25 +++--- simd/x86_64/jsimd.c | 16 ++-- strtest.c | 165 +++++++++++++++++++++++++++++++++++++++ tjbench.c | 4 + tjexample.c | 8 +- tjunittest.c | 7 +- tjutil.h | 5 -- turbojpeg-jni.c | 16 ++-- turbojpeg.c | 77 +++++++++++------- wrjpgcom.c | 6 +- 22 files changed, 414 insertions(+), 112 deletions(-) create mode 100644 strtest.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 639ea570..1198eced 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -360,7 +360,7 @@ if(MSVC) endif() endforeach() endif() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W3 /wd4996") + add_definitions(-D_CRT_NONSTDC_NO_WARNINGS) endif() if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") @@ -709,6 +709,8 @@ if(WITH_FUZZ) add_subdirectory(fuzz) endif() +add_executable(strtest strtest.c) + add_subdirectory(md5) if(MSVC_IDE OR XCODE) diff --git a/cjpeg.c b/cjpeg.c index 41ef5c18..41020a8f 100644 --- a/cjpeg.c +++ b/cjpeg.c @@ -5,7 +5,7 @@ * Copyright (C) 1991-1998, Thomas G. Lane. * Modified 2003-2011 by Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2013-2014, 2017, 2019-2021, D. R. Commander. + * Copyright (C) 2010, 2013-2014, 2017, 2019-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -27,6 +27,10 @@ * works regardless of which command line style is used. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #ifdef CJPEG_FUZZER #define JPEG_INTERNALS #endif diff --git a/djpeg.c b/djpeg.c index dfd6d900..5190e687 100644 --- a/djpeg.c +++ b/djpeg.c @@ -28,6 +28,10 @@ * works regardless of which command line style is used. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ #include "jversion.h" /* for version message */ #include "jconfigint.h" diff --git a/jerror.c b/jerror.c index 936c4f5d..d5447029 100644 --- a/jerror.c +++ b/jerror.c @@ -3,8 +3,8 @@ * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1998, Thomas G. Lane. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -189,13 +189,13 @@ format_message(j_common_ptr cinfo, char *buffer) /* Format the message into the passed buffer */ if (isstring) - sprintf(buffer, msgtext, err->msg_parm.s); + snprintf(buffer, JMSG_LENGTH_MAX, msgtext, err->msg_parm.s); else - sprintf(buffer, msgtext, - err->msg_parm.i[0], err->msg_parm.i[1], - err->msg_parm.i[2], err->msg_parm.i[3], - err->msg_parm.i[4], err->msg_parm.i[5], - err->msg_parm.i[6], err->msg_parm.i[7]); + snprintf(buffer, JMSG_LENGTH_MAX, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); } diff --git a/jinclude.h b/jinclude.h index 6ed982d3..120614b2 100644 --- a/jinclude.h +++ b/jinclude.h @@ -3,8 +3,8 @@ * * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1994, Thomas G. Lane. - * It was modified by The libjpeg-turbo Project to include only code relevant - * to libjpeg-turbo. + * libjpeg-turbo Modifications: + * Copyright (C) 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -17,10 +17,13 @@ * JPEG library. Most applications need only include jpeglib.h. */ +#ifndef __JINCLUDE_H__ +#define __JINCLUDE_H__ /* Include auto-config file to find out which system include files we need. */ #include "jconfig.h" /* auto configuration options */ +#include "jconfigint.h" #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* @@ -34,3 +37,97 @@ #include #include #include + +/* + * These macros/inline functions facilitate using Microsoft's "safe string" + * functions with Visual Studio builds without the need to scatter #ifdefs + * throughout the code base. + */ + + +#ifndef NO_GETENV + +#ifdef _MSC_VER + +static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name) +{ + size_t required_size; + + return (int)getenv_s(&required_size, buffer, buffer_size, name); +} + +#else /* _MSC_VER */ + +#include + +/* This provides a similar interface to the Microsoft/C11 getenv_s() function, + * but other than parameter validation, it has no advantages over getenv(). + */ + +static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name) +{ + char *env; + + if (!buffer) { + if (buffer_size == 0) + return 0; + else + return (errno = EINVAL); + } + if (buffer_size == 0) + return (errno = EINVAL); + if (!name) { + *buffer = 0; + return 0; + } + + env = getenv(name); + if (!env) + { + *buffer = 0; + return 0; + } + + if (strlen(env) + 1 > buffer_size) { + *buffer = 0; + return ERANGE; + } + + strncpy(buffer, env, buffer_size); + + return 0; +} + +#endif /* _MSC_VER */ + +#endif /* NO_GETENV */ + + +#ifndef NO_PUTENV + +#ifdef _WIN32 + +#define PUTENV_S(name, value) _putenv_s(name, value) + +#else + +/* This provides a similar interface to the Microsoft _putenv_s() function, but + * other than parameter validation, it has no advantages over setenv(). + */ + +static INLINE int PUTENV_S(const char *name, const char *value) +{ + if (!name || !value) + return (errno = EINVAL); + + setenv(name, value, 1); + + return errno; +} + +#endif /* _WIN32 */ + +#endif /* NO_PUTENV */ + + +#endif /* JINCLUDE_H */ diff --git a/jmemmgr.c b/jmemmgr.c index d053813d..8f5a4ab1 100644 --- a/jmemmgr.c +++ b/jmemmgr.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1991-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2016, 2021, D. R. Commander. + * Copyright (C) 2016, 2021-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -1156,12 +1156,16 @@ jinit_memory_mgr(j_common_ptr cinfo) */ #ifndef NO_GETENV { - char *memenv; + char memenv[30] = { 0 }; - if ((memenv = getenv("JPEGMEM")) != NULL) { + if (!GETENV_S(memenv, 30, "JPEGMEM") && strlen(memenv) > 0) { char ch = 'x'; +#ifdef _MSC_VER + if (sscanf_s(memenv, "%ld%c", &max_to_use, &ch, 1) > 0) { +#else if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { +#endif if (ch == 'm' || ch == 'M') max_to_use *= 1000L; mem->pub.max_memory_to_use = max_to_use * 1000L; diff --git a/jpegtran.c b/jpegtran.c index 7dd27232..4c7ab772 100644 --- a/jpegtran.c +++ b/jpegtran.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1995-2019, Thomas G. Lane, Guido Vollbeding. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2014, 2017, 2019-2021, D. R. Commander. + * Copyright (C) 2010, 2014, 2017, 2019-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -14,6 +14,10 @@ * provides some lossless and sort-of-lossless transformations of JPEG data. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ #include "transupp.h" /* Support routines for jpegtran */ #include "jversion.h" /* for version message */ diff --git a/md5/md5hl.c b/md5/md5hl.c index 8a4a762f..849a1366 100644 --- a/md5/md5hl.c +++ b/md5/md5hl.c @@ -6,7 +6,7 @@ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp * ---------------------------------------------------------------------------- * libjpeg-turbo Modifications: - * Copyright (C)2016, 2018-2019 D. R. Commander. All Rights Reserved. + * Copyright (C)2016, 2018-2019, 2022 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: @@ -34,6 +34,10 @@ * ---------------------------------------------------------------------------- */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include #include #include diff --git a/rdjpgcom.c b/rdjpgcom.c index fc0c08c0..9910a634 100644 --- a/rdjpgcom.c +++ b/rdjpgcom.c @@ -15,6 +15,10 @@ * JPEG markers. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ #include "jinclude.h" /* get auto-config symbols, */ diff --git a/rdswitch.c b/rdswitch.c index f9ed70f5..33449c86 100644 --- a/rdswitch.c +++ b/rdswitch.c @@ -17,6 +17,10 @@ * -sample HxV[,HxV,...] Set component sampling factors */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */ #include /* to declare isdigit(), isspace() */ diff --git a/simd/arm/aarch32/jsimd.c b/simd/arm/aarch32/jsimd.c index fac55dfb..e3adf23d 100644 --- a/simd/arm/aarch32/jsimd.c +++ b/simd/arm/aarch32/jsimd.c @@ -3,7 +3,7 @@ * * Copyright 2009 Pierre Ossman for Cendio AB * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, D. R. Commander. + * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander. * Copyright (C) 2015-2016, 2018, Matthieu Darbois. * Copyright (C) 2019, Google LLC. * Copyright (C) 2020, Arm Limited. @@ -105,7 +105,7 @@ LOCAL(void) init_simd(void) { #ifndef NO_GETENV - char *env = NULL; + char env[2] = { 0 }; #endif #if !defined(__ARM_NEON__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)) int bufsize = 1024; /* an initial guess for the line buffer size limit */ @@ -131,14 +131,11 @@ init_simd(void) #ifndef NO_GETENV /* Force different settings through environment variables */ - env = getenv("JSIMD_FORCENEON"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENEON") && !strcmp(env, "1")) simd_support = JSIMD_NEON; - env = getenv("JSIMD_FORCENONE"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1")) simd_support = 0; - env = getenv("JSIMD_NOHUFFENC"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1")) simd_huffman = 0; #endif } diff --git a/simd/arm/aarch64/jsimd.c b/simd/arm/aarch64/jsimd.c index 8570b82c..604d5472 100644 --- a/simd/arm/aarch64/jsimd.c +++ b/simd/arm/aarch64/jsimd.c @@ -3,7 +3,7 @@ * * Copyright 2009 Pierre Ossman for Cendio AB * Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies). - * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, D. R. Commander. + * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, D. R. Commander. * Copyright (C) 2015-2016, 2018, Matthieu Darbois. * Copyright (C) 2020, Arm Limited. * @@ -125,7 +125,7 @@ LOCAL(void) init_simd(void) { #ifndef NO_GETENV - char *env = NULL; + char env[2] = { 0 }; #endif #if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__) int bufsize = 1024; /* an initial guess for the line buffer size limit */ @@ -147,24 +147,19 @@ init_simd(void) #ifndef NO_GETENV /* Force different settings through environment variables */ - env = getenv("JSIMD_FORCENEON"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENEON") && !strcmp(env, "1")) simd_support = JSIMD_NEON; - env = getenv("JSIMD_FORCENONE"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1")) simd_support = 0; - env = getenv("JSIMD_NOHUFFENC"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1")) simd_huffman = 0; - env = getenv("JSIMD_FASTLD3"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FASTLD3") && !strcmp(env, "1")) simd_features |= JSIMD_FASTLD3; - if ((env != NULL) && (strcmp(env, "0") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FASTLD3") && !strcmp(env, "0")) simd_features &= ~JSIMD_FASTLD3; - env = getenv("JSIMD_FASTST3"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FASTST3") && !strcmp(env, "1")) simd_features |= JSIMD_FASTST3; - if ((env != NULL) && (strcmp(env, "0") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FASTST3") && !strcmp(env, "0")) simd_features &= ~JSIMD_FASTST3; #endif } diff --git a/simd/i386/jsimd.c b/simd/i386/jsimd.c index 563949a0..80bc821f 100644 --- a/simd/i386/jsimd.c +++ b/simd/i386/jsimd.c @@ -2,7 +2,7 @@ * jsimd_i386.c * * Copyright 2009 Pierre Ossman for Cendio AB - * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, D. R. Commander. + * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander. * Copyright (C) 2015-2016, 2018, Matthieu Darbois. * * Based on the x86 SIMD extension for IJG JPEG library, @@ -44,7 +44,7 @@ LOCAL(void) init_simd(void) { #ifndef NO_GETENV - char *env = NULL; + char env[2] = { 0 }; #endif if (simd_support != ~0U) @@ -54,26 +54,19 @@ init_simd(void) #ifndef NO_GETENV /* Force different settings through environment variables */ - env = getenv("JSIMD_FORCEMMX"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCEMMX") && !strcmp(env, "1")) simd_support &= JSIMD_MMX; - env = getenv("JSIMD_FORCE3DNOW"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCE3DNOW") && !strcmp(env, "1")) simd_support &= JSIMD_3DNOW | JSIMD_MMX; - env = getenv("JSIMD_FORCESSE"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCESSE") && !strcmp(env, "1")) simd_support &= JSIMD_SSE | JSIMD_MMX; - env = getenv("JSIMD_FORCESSE2"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCESSE2") && !strcmp(env, "1")) simd_support &= JSIMD_SSE2; - env = getenv("JSIMD_FORCEAVX2"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCEAVX2") && !strcmp(env, "1")) simd_support &= JSIMD_AVX2; - env = getenv("JSIMD_FORCENONE"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1")) simd_support = 0; - env = getenv("JSIMD_NOHUFFENC"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1")) simd_huffman = 0; #endif } diff --git a/simd/x86_64/jsimd.c b/simd/x86_64/jsimd.c index eb766799..584a010a 100644 --- a/simd/x86_64/jsimd.c +++ b/simd/x86_64/jsimd.c @@ -2,7 +2,7 @@ * jsimd_x86_64.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, 2022, D. R. Commander. * Copyright (C) 2015-2016, 2018, Matthieu Darbois. * * Based on the x86 SIMD extension for IJG JPEG library, @@ -44,7 +44,7 @@ LOCAL(void) init_simd(void) { #ifndef NO_GETENV - char *env = NULL; + char env[2] = { 0 }; #endif if (simd_support != ~0U) @@ -54,17 +54,13 @@ init_simd(void) #ifndef NO_GETENV /* Force different settings through environment variables */ - env = getenv("JSIMD_FORCESSE2"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCESSE2") && !strcmp(env, "1")) simd_support &= JSIMD_SSE2; - env = getenv("JSIMD_FORCEAVX2"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCEAVX2") && !strcmp(env, "1")) simd_support &= JSIMD_AVX2; - env = getenv("JSIMD_FORCENONE"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_FORCENONE") && !strcmp(env, "1")) simd_support = 0; - env = getenv("JSIMD_NOHUFFENC"); - if ((env != NULL) && (strcmp(env, "1") == 0)) + if (!GETENV_S(env, 2, "JSIMD_NOHUFFENC") && !strcmp(env, "1")) simd_huffman = 0; #endif } diff --git a/strtest.c b/strtest.c new file mode 100644 index 00000000..ceaad91a --- /dev/null +++ b/strtest.c @@ -0,0 +1,165 @@ +/* + * Copyright (C)2022 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: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of the libjpeg-turbo Project nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "jinclude.h" + + +#define CHECK_VALUE(actual, expected, desc) \ + if (actual != expected) { \ + printf("ERROR in line %d: " desc " is %d, should be %d\n", \ + __LINE__, actual, expected); \ + return -1; \ + } + +#define CHECK_ERRNO(errno_return, expected_errno) \ + CHECK_VALUE(errno_return, expected_errno, "Return value") \ + CHECK_VALUE(errno, expected_errno, "errno") \ + + +#ifdef _MSC_VER + +void invalid_parameter_handler(const wchar_t *expression, + const wchar_t *function, const wchar_t *file, + unsigned int line, uintptr_t pReserved) +{ +} + +#endif + + +int main(int argc, char **argv) +{ + int err; + char env[3]; + +#ifdef _MSC_VER + _set_invalid_parameter_handler(invalid_parameter_handler); +#endif + + /***************************************************************************/ + +#ifndef NO_PUTENV + + printf("PUTENV_S():\n"); + + errno = 0; + err = PUTENV_S(NULL, "12"); + CHECK_ERRNO(err, EINVAL); + + errno = 0; + err = PUTENV_S("TESTENV", NULL); + CHECK_ERRNO(err, EINVAL); + + errno = 0; + err = PUTENV_S("TESTENV", "12"); + CHECK_ERRNO(err, 0); + + printf("SUCCESS!\n\n"); + +#endif + + /***************************************************************************/ + +#ifndef NO_GETENV + + printf("GETENV_S():\n"); + + errno = 0; + env[0] = 1; + env[1] = 2; + env[2] = 3; + err = GETENV_S(env, 3, NULL); + CHECK_ERRNO(err, 0); + CHECK_VALUE(env[0], 0, "env[0]"); + CHECK_VALUE(env[1], 2, "env[1]"); + CHECK_VALUE(env[2], 3, "env[2]"); + + errno = 0; + env[0] = 1; + env[1] = 2; + env[2] = 3; + err = GETENV_S(env, 3, "TESTENV2"); + CHECK_ERRNO(err, 0); + CHECK_VALUE(env[0], 0, "env[0]"); + CHECK_VALUE(env[1], 2, "env[1]"); + CHECK_VALUE(env[2], 3, "env[2]"); + + errno = 0; + err = GETENV_S(NULL, 3, "TESTENV"); + CHECK_ERRNO(err, EINVAL); + + errno = 0; + err = GETENV_S(NULL, 0, "TESTENV"); + CHECK_ERRNO(err, 0); + + errno = 0; + env[0] = 1; + err = GETENV_S(env, 0, "TESTENV"); + CHECK_ERRNO(err, EINVAL); + CHECK_VALUE(env[0], 1, "env[0]"); + + errno = 0; + env[0] = 1; + env[1] = 2; + env[2] = 3; + err = GETENV_S(env, 1, "TESTENV"); + CHECK_VALUE(err, ERANGE, "Return value"); + CHECK_VALUE(errno, 0, "errno"); + CHECK_VALUE(env[0], 0, "env[0]"); + CHECK_VALUE(env[1], 2, "env[1]"); + CHECK_VALUE(env[2], 3, "env[2]"); + + errno = 0; + env[0] = 1; + env[1] = 2; + env[2] = 3; + err = GETENV_S(env, 2, "TESTENV"); + CHECK_VALUE(err, ERANGE, "Return value"); + CHECK_VALUE(errno, 0, "errno"); + CHECK_VALUE(env[0], 0, "env[0]"); + CHECK_VALUE(env[1], 2, "env[1]"); + CHECK_VALUE(env[2], 3, "env[2]"); + + errno = 0; + env[0] = 1; + env[1] = 2; + env[2] = 3; + err = GETENV_S(env, 3, "TESTENV"); + CHECK_ERRNO(err, 0); + CHECK_VALUE(env[0], '1', "env[0]"); + CHECK_VALUE(env[1], '2', "env[1]"); + CHECK_VALUE(env[2], 0, "env[2]"); + + printf("SUCCESS!\n\n"); + +#endif + + /***************************************************************************/ + + return 0; +} diff --git a/tjbench.c b/tjbench.c index 344cb4cb..b7878b61 100644 --- a/tjbench.c +++ b/tjbench.c @@ -26,6 +26,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include #include #include diff --git a/tjexample.c b/tjexample.c index a9cd865b..505c9dd4 100644 --- a/tjexample.c +++ b/tjexample.c @@ -1,6 +1,6 @@ /* - * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021 D. R. Commander. - * All Rights Reserved. + * Copyright (C)2011-2012, 2014-2015, 2017, 2019, 2021-2022 + * 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: @@ -32,6 +32,10 @@ * images using the TurboJPEG C API */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include #include #include diff --git a/tjunittest.c b/tjunittest.c index f59939fd..bda65f95 100644 --- a/tjunittest.c +++ b/tjunittest.c @@ -1,5 +1,6 @@ /* - * Copyright (C)2009-2014, 2017-2019 D. R. Commander. All Rights Reserved. + * Copyright (C)2009-2014, 2017-2019, 2022 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: @@ -30,6 +31,10 @@ * This program tests the various code paths in the TurboJPEG C Wrapper */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #include #include #include diff --git a/tjutil.h b/tjutil.h index 8542bab9..fc8a17a7 100644 --- a/tjutil.h +++ b/tjutil.h @@ -27,11 +27,6 @@ */ #ifdef _WIN32 -#ifndef __MINGW32__ -#include -#define snprintf(str, n, format, ...) \ - _snprintf_s(str, n, _TRUNCATE, format, ##__VA_ARGS__) -#endif #define strcasecmp stricmp #define strncasecmp strnicmp #endif diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c index 4fa6dfdf..dc80e23c 100644 --- a/turbojpeg-jni.c +++ b/turbojpeg-jni.c @@ -1,5 +1,5 @@ /* - * Copyright (C)2011-2021 D. R. Commander. All Rights Reserved. + * Copyright (C)2011-2022 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: @@ -29,9 +29,7 @@ #include #include #include "turbojpeg.h" -#ifdef WIN32 -#include "tjutil.h" -#endif +#include "jinclude.h" #include #include "java/org_libjpegturbo_turbojpeg_TJCompressor.h" #include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h" @@ -88,10 +86,7 @@ BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "handle", "J")); \ handle = (tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid); -#ifdef _WIN32 -#define setenv(envvar, value, dummy) _putenv_s(envvar, value) -#endif - +#ifndef NO_PUTENV #define PROP2ENV(property, envvar) { \ if ((jName = (*env)->NewStringUTF(env, property)) != NULL) { \ jboolean exception; \ @@ -99,11 +94,12 @@ exception = (*env)->ExceptionCheck(env); \ if (jValue && !exception && \ (value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \ - setenv(envvar, value, 1); \ + PUTENV_S(envvar, value); \ (*env)->ReleaseStringUTFChars(env, jValue, value); \ } \ } \ } +#endif #define SAFE_RELEASE(javaArray, cArray) { \ if (javaArray && cArray) \ @@ -122,10 +118,12 @@ static int ProcessSystemProperties(JNIEnv *env) BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")); +#ifndef NO_PUTENV PROP2ENV("turbojpeg.optimize", "TJ_OPTIMIZE"); PROP2ENV("turbojpeg.arithmetic", "TJ_ARITHMETIC"); PROP2ENV("turbojpeg.restart", "TJ_RESTART"); PROP2ENV("turbojpeg.progressive", "TJ_PROGRESSIVE"); +#endif return 0; bailout: diff --git a/turbojpeg.c b/turbojpeg.c index d780dc25..71cbc46b 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -196,10 +196,19 @@ static int cs2pf[JPEG_NUMCS] = { snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ retval = -1; goto bailout; \ } +#ifdef _MSC_VER +#define THROW_UNIX(m) { \ + char strerrorBuf[80] = { 0 }; \ + strerror_s(strerrorBuf, 80, errno); \ + snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerrorBuf); \ + retval = -1; goto bailout; \ +} +#else #define THROW_UNIX(m) { \ snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, strerror(errno)); \ retval = -1; goto bailout; \ } +#endif #define THROW(m) { \ snprintf(this->errStr, JMSG_LENGTH_MAX, "%s", m); \ this->isInstanceError = TRUE; THROWG(m) \ @@ -271,7 +280,7 @@ static void setCompDefaults(struct jpeg_compress_struct *cinfo, int flags) { #ifndef NO_GETENV - char *env = NULL; + char env[7] = { 0 }; #endif cinfo->in_color_space = pf2cs[pixelFormat]; @@ -279,18 +288,21 @@ static void setCompDefaults(struct jpeg_compress_struct *cinfo, jpeg_set_defaults(cinfo); #ifndef NO_GETENV - if ((env = getenv("TJ_OPTIMIZE")) != NULL && strlen(env) > 0 && - !strcmp(env, "1")) + if (!GETENV_S(env, 7, "TJ_OPTIMIZE") && !strcmp(env, "1")) cinfo->optimize_coding = TRUE; - if ((env = getenv("TJ_ARITHMETIC")) != NULL && strlen(env) > 0 && - !strcmp(env, "1")) + if (!GETENV_S(env, 7, "TJ_ARITHMETIC") && !strcmp(env, "1")) cinfo->arith_code = TRUE; - if ((env = getenv("TJ_RESTART")) != NULL && strlen(env) > 0) { + if (!GETENV_S(env, 7, "TJ_RESTART") && strlen(env) > 0) { int temp = -1; char tempc = 0; +#ifdef _MSC_VER + if (sscanf_s(env, "%d%c", &temp, &tempc, 1) >= 1 && temp >= 0 && + temp <= 65535) { +#else if (sscanf(env, "%d%c", &temp, &tempc) >= 1 && temp >= 0 && temp <= 65535) { +#endif if (toupper(tempc) == 'B') { cinfo->restart_interval = temp; cinfo->restart_in_rows = 0; @@ -317,8 +329,7 @@ static void setCompDefaults(struct jpeg_compress_struct *cinfo, if (flags & TJFLAG_PROGRESSIVE) jpeg_simple_progression(cinfo); #ifndef NO_GETENV - else if ((env = getenv("TJ_PROGRESSIVE")) != NULL && strlen(env) > 0 && - !strcmp(env, "1")) + else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1")) jpeg_simple_progression(cinfo); #endif @@ -697,9 +708,9 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, cinfo->image_height = height; #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif if (flags & TJFLAG_NOREALLOC) { @@ -799,9 +810,9 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf, cinfo->image_height = height; #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags); @@ -1009,9 +1020,9 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle, cinfo->image_height = height; #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif if (flags & TJFLAG_NOREALLOC) { @@ -1295,9 +1306,9 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, THROW("tjDecompress2(): Invalid argument"); #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif if (flags & TJFLAG_LIMITSCANS) { @@ -1471,9 +1482,9 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle, dinfo->image_height = height; #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE; @@ -1643,9 +1654,9 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle, THROW("tjDecompressToYUVPlanes(): Invalid argument"); #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif if (flags & TJFLAG_LIMITSCANS) { @@ -1906,9 +1917,9 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, THROW("tjTransform(): Invalid argument"); #ifndef NO_PUTENV - if (flags & TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); - else if (flags & TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); - else if (flags & TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); + if (flags & TJFLAG_FORCEMMX) PUTENV_S("JSIMD_FORCEMMX", "1"); + else if (flags & TJFLAG_FORCESSE) PUTENV_S("JSIMD_FORCESSE", "1"); + else if (flags & TJFLAG_FORCESSE2) PUTENV_S("JSIMD_FORCESSE2", "1"); #endif if (flags & TJFLAG_LIMITSCANS) { @@ -2075,7 +2086,11 @@ DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width, this = (tjinstance *)handle; cinfo = &this->cinfo; +#ifdef _MSC_VER + if (fopen_s(&file, filename, "rb") || file == NULL) +#else if ((file = fopen(filename, "rb")) == NULL) +#endif THROW_UNIX("tjLoadImage(): Cannot open input file"); if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF) @@ -2171,7 +2186,11 @@ DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer, this = (tjinstance *)handle; dinfo = &this->dinfo; +#ifdef _MSC_VER + if (fopen_s(&file, filename, "wb") || file == NULL) +#else if ((file = fopen(filename, "wb")) == NULL) +#endif THROW_UNIX("tjSaveImage(): Cannot open output file"); if (setjmp(this->jerr.setjmp_buffer)) { diff --git a/wrjpgcom.c b/wrjpgcom.c index 6a4dc6bc..3ee08a0e 100644 --- a/wrjpgcom.c +++ b/wrjpgcom.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1994-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2014, D. R. Commander. + * Copyright (C) 2014, 2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -14,6 +14,10 @@ * JPEG markers. */ +#ifdef _MSC_VER +#define _CRT_SECURE_NO_DEPRECATE +#endif + #define JPEG_CJPEG_DJPEG /* to get the command-line config symbols */ #include "jinclude.h" /* get auto-config symbols, */ From 13377e6b387e192dd6a053c5f70e465248c388ef Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 11 Feb 2022 13:58:31 -0600 Subject: [PATCH 51/56] MSVC: Eliminate int conversion warnings (C4244) --- jcphuff.c | 4 ++-- jdarith.c | 8 ++++---- jdphuff.c | 10 +++++----- rdppm.c | 16 ++++++++-------- tjbench.c | 9 +++++---- turbojpeg.c | 15 +++++++++------ 6 files changed, 33 insertions(+), 29 deletions(-) diff --git a/jcphuff.c b/jcphuff.c index 156ae634..872e570b 100644 --- a/jcphuff.c +++ b/jcphuff.c @@ -584,8 +584,8 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data) continue; \ /* For a negative coef, want temp2 = bitwise complement of abs(coef) */ \ temp2 ^= temp; \ - values[k] = temp; \ - values[k + DCTSIZE2] = temp2; \ + values[k] = (JCOEF)temp; \ + values[k + DCTSIZE2] = (JCOEF)temp2; \ zerobits |= ((size_t)1U) << k; \ } \ } diff --git a/jdarith.c b/jdarith.c index 431b46cd..21575e80 100644 --- a/jdarith.c +++ b/jdarith.c @@ -471,17 +471,17 @@ decode_mcu_AC_refine(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) if (*thiscoef) { /* previously nonzero coef */ if (arith_decode(cinfo, st + 2)) { if (*thiscoef < 0) - *thiscoef += m1; + *thiscoef += (JCOEF)m1; else - *thiscoef += p1; + *thiscoef += (JCOEF)p1; } break; } if (arith_decode(cinfo, st + 1)) { /* newly nonzero coef */ if (arith_decode(cinfo, entropy->fixed_bin)) - *thiscoef = m1; + *thiscoef = (JCOEF)m1; else - *thiscoef = p1; + *thiscoef = (JCOEF)p1; break; } st += 3; k++; diff --git a/jdphuff.c b/jdphuff.c index c6d82ca1..9680ebcb 100644 --- a/jdphuff.c +++ b/jdphuff.c @@ -4,7 +4,7 @@ * This file was part of the Independent JPEG Group's software: * Copyright (C) 1995-1997, Thomas G. Lane. * libjpeg-turbo Modifications: - * Copyright (C) 2015-2016, 2018-2021, D. R. Commander. + * Copyright (C) 2015-2016, 2018-2022, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -578,9 +578,9 @@ decode_mcu_AC_refine(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) if (GET_BITS(1)) { if ((*thiscoef & p1) == 0) { /* do nothing if already set it */ if (*thiscoef >= 0) - *thiscoef += p1; + *thiscoef += (JCOEF)p1; else - *thiscoef += m1; + *thiscoef += (JCOEF)m1; } } } else { @@ -612,9 +612,9 @@ decode_mcu_AC_refine(j_decompress_ptr cinfo, JBLOCKROW *MCU_data) if (GET_BITS(1)) { if ((*thiscoef & p1) == 0) { /* do nothing if already changed it */ if (*thiscoef >= 0) - *thiscoef += p1; + *thiscoef += (JCOEF)p1; else - *thiscoef += m1; + *thiscoef += (JCOEF)m1; } } } diff --git a/rdppm.c b/rdppm.c index 409497d6..294749a4 100644 --- a/rdppm.c +++ b/rdppm.c @@ -178,10 +178,10 @@ get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) ptr = source->pub.buffer[0]; if (maxval == MAXJSAMPLE) { if (aindex >= 0) - GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), + GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), ptr[aindex] = 0xFF;) else - GRAY_RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), {}) + GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {}) } else { if (aindex >= 0) GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], @@ -208,7 +208,7 @@ get_text_gray_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) ptr = source->pub.buffer[0]; if (maxval == MAXJSAMPLE) { for (col = cinfo->image_width; col > 0; col--) { - JSAMPLE gray = read_pbm_integer(cinfo, infile, maxval); + JSAMPLE gray = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval); rgb_to_cmyk(gray, gray, gray, ptr, ptr + 1, ptr + 2, ptr + 3); ptr += 4; } @@ -252,10 +252,10 @@ get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) ptr = source->pub.buffer[0]; if (maxval == MAXJSAMPLE) { if (aindex >= 0) - RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), + RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), ptr[aindex] = 0xFF;) else - RGB_READ_LOOP(read_pbm_integer(cinfo, infile, maxval), {}) + RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {}) } else { if (aindex >= 0) RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], @@ -282,9 +282,9 @@ get_text_rgb_cmyk_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo) ptr = source->pub.buffer[0]; if (maxval == MAXJSAMPLE) { for (col = cinfo->image_width; col > 0; col--) { - JSAMPLE r = read_pbm_integer(cinfo, infile, maxval); - JSAMPLE g = read_pbm_integer(cinfo, infile, maxval); - JSAMPLE b = read_pbm_integer(cinfo, infile, maxval); + JSAMPLE r = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval); + JSAMPLE g = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval); + JSAMPLE b = (JSAMPLE)read_pbm_integer(cinfo, infile, maxval); rgb_to_cmyk(r, g, b, ptr, ptr + 1, ptr + 2, ptr + 3); ptr += 4; } diff --git a/tjbench.c b/tjbench.c index b7878b61..8730a022 100644 --- a/tjbench.c +++ b/tjbench.c @@ -292,16 +292,17 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf, if (y > 255) y = 255; if (y < 0) y = 0; - dstBuf[rindex] = abs(dstBuf[rindex] - y); - dstBuf[gindex] = abs(dstBuf[gindex] - y); - dstBuf[bindex] = abs(dstBuf[bindex] - y); + dstBuf[rindex] = (unsigned char)abs(dstBuf[rindex] - y); + dstBuf[gindex] = (unsigned char)abs(dstBuf[gindex] - y); + dstBuf[bindex] = (unsigned char)abs(dstBuf[bindex] - y); } } } else { for (row = 0; row < h; row++) for (col = 0; col < w * ps; col++) dstBuf[pitch * row + col] = - abs(dstBuf[pitch * row + col] - srcBuf[pitch * row + col]); + (unsigned char)abs(dstBuf[pitch * row + col] - + srcBuf[pitch * row + col]); } if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1) THROW_TJG("saving bitmap"); diff --git a/turbojpeg.c b/turbojpeg.c index 71cbc46b..d5e31360 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -680,7 +680,8 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) { - int i, retval = 0, alloc = 1; + int i, retval = 0; + boolean alloc = TRUE; JSAMPROW *row_pointer = NULL; GET_CINSTANCE(handle) @@ -714,7 +715,7 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, #endif if (flags & TJFLAG_NOREALLOC) { - alloc = 0; *jpegSize = tjBufSize(width, height, jpegSubsamp); + alloc = FALSE; *jpegSize = tjBufSize(width, height, jpegSubsamp); } jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); setCompDefaults(cinfo, pixelFormat, jpegSubsamp, jpegQual, flags); @@ -988,7 +989,8 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle, unsigned long *jpegSize, int jpegQual, int flags) { - int i, row, retval = 0, alloc = 1; + int i, row, retval = 0; + boolean alloc = TRUE; int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS], tmpbufsize = 0, usetmpbuf = 0, th[MAX_COMPONENTS]; JSAMPLE *_tmpbuf = NULL, *ptr; @@ -1026,7 +1028,7 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle, #endif if (flags & TJFLAG_NOREALLOC) { - alloc = 0; *jpegSize = tjBufSize(width, height, subsamp); + alloc = FALSE; *jpegSize = tjBufSize(width, height, subsamp); } jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags); @@ -1904,7 +1906,8 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, { jpeg_transform_info *xinfo = NULL; jvirt_barray_ptr *srccoefs, *dstcoefs; - int retval = 0, alloc = 1, i, jpegSubsamp, saveMarkers = 0; + int retval = 0, i, jpegSubsamp, saveMarkers = 0; + boolean alloc = TRUE; struct my_progress_mgr progress; GET_INSTANCE(handle); @@ -2000,7 +2003,7 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf, w = xinfo[i].crop_width; h = xinfo[i].crop_height; } if (flags & TJFLAG_NOREALLOC) { - alloc = 0; dstSizes[i] = tjBufSize(w, h, jpegSubsamp); + alloc = FALSE; dstSizes[i] = tjBufSize(w, h, jpegSubsamp); } if (!(t[i].options & TJXOPT_NOOUTPUT)) jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc); From eb21c023ab6e70a0e1027592ea618ce3fadbd547 Mon Sep 17 00:00:00 2001 From: DRC Date: Tue, 22 Feb 2022 14:01:07 -0600 Subject: [PATCH 52/56] Eliminate incompatible pointer type warnings (C4057 in MSVC and -Wincompatible-pointer-types in GCC/Clang) --- turbojpeg-jni.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c index dc80e23c..ba76634e 100644 --- a/turbojpeg-jni.c +++ b/turbojpeg-jni.c @@ -334,6 +334,7 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanes[3] = { NULL, NULL, NULL }; + jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 }; int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 }; unsigned char *jpegBuf = NULL; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; @@ -358,11 +359,15 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom if (ProcessSystemProperties(env) < 0) goto bailout; - (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets); + (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + srcOffsets[i] = srcOffsetsTmp[i]; - (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides); + (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + srcStrides[i] = srcStridesTmp[i]; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); @@ -415,6 +420,7 @@ static void TJCompressor_encodeYUV jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL }; unsigned char *dstPlanes[3] = { NULL, NULL, NULL }; + jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 }; int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 }; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; @@ -440,11 +446,15 @@ static void TJCompressor_encodeYUV if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize) THROW_ARG("Source buffer is not large enough"); - (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets); + (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + dstOffsets[i] = dstOffsetsTmp[i]; - (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides); + (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + dstStrides[i] = dstStridesTmp[i]; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp); @@ -784,6 +794,7 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress jbyteArray jDstPlanes[3] = { NULL, NULL, NULL }; unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL }; unsigned char *dstPlanes[3] = { NULL, NULL, NULL }; + jint dstOffsetsTmp[3] = { 0, 0, 0 }, dstStridesTmp[3] = { 0, 0, 0 }; int dstOffsets[3] = { 0, 0, 0 }, dstStrides[3] = { 0, 0, 0 }; int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0; int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0; @@ -818,11 +829,15 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress if (i >= nsf) THROW_ARG("Could not scale down to desired image dimensions"); - (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsets); + (*env)->GetIntArrayRegion(env, jDstOffsets, 0, nc, dstOffsetsTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + dstOffsets[i] = dstOffsetsTmp[i]; - (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStrides); + (*env)->GetIntArrayRegion(env, jDstStrides, 0, nc, dstStridesTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + dstStrides[i] = dstStridesTmp[i]; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight, @@ -912,6 +927,7 @@ static void TJDecompressor_decodeYUV jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL }; const unsigned char *srcPlanes[3] = { NULL, NULL, NULL }; + jint srcOffsetsTmp[3] = { 0, 0, 0 }, srcStridesTmp[3] = { 0, 0, 0 }; int srcOffsets[3] = { 0, 0, 0 }, srcStrides[3] = { 0, 0, 0 }; unsigned char *dstBuf = NULL; int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i; @@ -937,11 +953,15 @@ static void TJDecompressor_decodeYUV if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize) THROW_ARG("Destination buffer is not large enough"); - (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsets); + (*env)->GetIntArrayRegion(env, jSrcOffsets, 0, nc, srcOffsetsTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + srcOffsets[i] = srcOffsetsTmp[i]; - (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStrides); + (*env)->GetIntArrayRegion(env, jSrcStrides, 0, nc, srcStridesTmp); if ((*env)->ExceptionCheck(env)) goto bailout; + for (i = 0; i < 3; i++) + srcStrides[i] = srcStridesTmp[i]; for (i = 0; i < nc; i++) { int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); From d640a457305164417a60f30c6457d316f0b44a9d Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 11 Feb 2022 14:12:25 -0600 Subject: [PATCH 53/56] AppVeyor: Test strict MSVC compiler warnings --- appveyor.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index de09dd16..9fa3aae5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -47,6 +47,18 @@ build_script: bash c:/buildscripts/buildljt -d %MINGWPATH% -b /c/ljt.nightly -v + cmake --build . --target clean + + md win64 + + cd win64 + + bash c:/buildscripts/setupscripts/win64 -DCMAKE_C_FLAGS='-DWIN32 -D_WINDOWS -W4 -wd4100 -wd4127 -wd4245 -wd4324 -wd4701 -wd4702 -wd4706 -WX' + + cd .. + + ninja + move c:\ljt.nightly\files\*.tar.gz . move c:\ljt.nightly\files\*.exe . From 147548c0559c6eee4fce946aec29bda41823e21d Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Mon, 6 Sep 2021 11:31:37 +0100 Subject: [PATCH 54/56] Neon/AArch64: Accelerate Huffman encoding - Make better use of 128-bit vector registers, thus reducing the number of Neon instructions required to construct the AC coefficient bitmap. - Refactor the Neon computations of 'nbits' and 'diff' to use shorter and higher-throughput instruction sequences. DRC's notes: This commit partially integrates #570. Arm reported a 1-4% speedup on Cortex-A55 and Neoverse-N1 cores when using recent compilers but little or no speedup with Clang 10. I observed no speedup with Clang 10 on my Cortex-A53 and Cortex-A72 cores. Thus, referring to #582, the primary purpose of this commit is to fix UBSan warnings regarding the shift operations previously located at Line 253: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/d640a457305164417a60f30c6457d316f0b44a9d/simd/arm/aarch64/jchuff-neon.c#L253 --- simd/arm/aarch64/jchuff-neon.c | 221 ++++++++++++++++----------------- 1 file changed, 109 insertions(+), 112 deletions(-) diff --git a/simd/arm/aarch64/jchuff-neon.c b/simd/arm/aarch64/jchuff-neon.c index f13fd1b5..e7c52bc0 100644 --- a/simd/arm/aarch64/jchuff-neon.c +++ b/simd/arm/aarch64/jchuff-neon.c @@ -158,73 +158,43 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, 7), row6, 5); /* DCT block is now in zig-zag order; start Huffman encoding process. */ - int16x8_t abs_row0 = vabsq_s16(row0); - int16x8_t abs_row1 = vabsq_s16(row1); - int16x8_t abs_row2 = vabsq_s16(row2); - int16x8_t abs_row3 = vabsq_s16(row3); - int16x8_t abs_row4 = vabsq_s16(row4); - int16x8_t abs_row5 = vabsq_s16(row5); - int16x8_t abs_row6 = vabsq_s16(row6); - int16x8_t abs_row7 = vabsq_s16(row7); - - /* For negative coeffs: diff = abs(coeff) -1 = ~abs(coeff) */ - uint16x8_t row0_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row0, vshrq_n_s16(row0, 15))); - uint16x8_t row1_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row1, vshrq_n_s16(row1, 15))); - uint16x8_t row2_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row2, vshrq_n_s16(row2, 15))); - uint16x8_t row3_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row3, vshrq_n_s16(row3, 15))); - uint16x8_t row4_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row4, vshrq_n_s16(row4, 15))); - uint16x8_t row5_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row5, vshrq_n_s16(row5, 15))); - uint16x8_t row6_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row6, vshrq_n_s16(row6, 15))); - uint16x8_t row7_diff = - vreinterpretq_u16_s16(veorq_s16(abs_row7, vshrq_n_s16(row7, 15))); /* Construct bitmap to accelerate encoding of AC coefficients. A set bit * means that the corresponding coefficient != 0. */ - uint8x8_t abs_row0_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row0), - vdupq_n_u16(0))); - uint8x8_t abs_row1_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row1), - vdupq_n_u16(0))); - uint8x8_t abs_row2_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row2), - vdupq_n_u16(0))); - uint8x8_t abs_row3_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row3), - vdupq_n_u16(0))); - uint8x8_t abs_row4_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row4), - vdupq_n_u16(0))); - uint8x8_t abs_row5_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row5), - vdupq_n_u16(0))); - uint8x8_t abs_row6_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row6), - vdupq_n_u16(0))); - uint8x8_t abs_row7_gt0 = vmovn_u16(vcgtq_u16(vreinterpretq_u16_s16(abs_row7), - vdupq_n_u16(0))); + uint16x8_t row0_ne_0 = vtstq_s16(row0, row0); + uint16x8_t row1_ne_0 = vtstq_s16(row1, row1); + uint16x8_t row2_ne_0 = vtstq_s16(row2, row2); + uint16x8_t row3_ne_0 = vtstq_s16(row3, row3); + uint16x8_t row4_ne_0 = vtstq_s16(row4, row4); + uint16x8_t row5_ne_0 = vtstq_s16(row5, row5); + uint16x8_t row6_ne_0 = vtstq_s16(row6, row6); + uint16x8_t row7_ne_0 = vtstq_s16(row7, row7); + + uint8x16_t row10_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row1_ne_0), + vreinterpretq_u8_u16(row0_ne_0)); + uint8x16_t row32_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row3_ne_0), + vreinterpretq_u8_u16(row2_ne_0)); + uint8x16_t row54_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row5_ne_0), + vreinterpretq_u8_u16(row4_ne_0)); + uint8x16_t row76_ne_0 = vuzp1q_u8(vreinterpretq_u8_u16(row7_ne_0), + vreinterpretq_u8_u16(row6_ne_0)); /* { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 } */ - const uint8x8_t bitmap_mask = - vreinterpret_u8_u64(vmov_n_u64(0x0102040810204080)); + const uint8x16_t bitmap_mask = + vreinterpretq_u8_u64(vdupq_n_u64(0x0102040810204080)); - abs_row0_gt0 = vand_u8(abs_row0_gt0, bitmap_mask); - abs_row1_gt0 = vand_u8(abs_row1_gt0, bitmap_mask); - abs_row2_gt0 = vand_u8(abs_row2_gt0, bitmap_mask); - abs_row3_gt0 = vand_u8(abs_row3_gt0, bitmap_mask); - abs_row4_gt0 = vand_u8(abs_row4_gt0, bitmap_mask); - abs_row5_gt0 = vand_u8(abs_row5_gt0, bitmap_mask); - abs_row6_gt0 = vand_u8(abs_row6_gt0, bitmap_mask); - abs_row7_gt0 = vand_u8(abs_row7_gt0, bitmap_mask); + uint8x16_t bitmap_rows_10 = vandq_u8(row10_ne_0, bitmap_mask); + uint8x16_t bitmap_rows_32 = vandq_u8(row32_ne_0, bitmap_mask); + uint8x16_t bitmap_rows_54 = vandq_u8(row54_ne_0, bitmap_mask); + uint8x16_t bitmap_rows_76 = vandq_u8(row76_ne_0, bitmap_mask); - uint8x8_t bitmap_rows_10 = vpadd_u8(abs_row1_gt0, abs_row0_gt0); - uint8x8_t bitmap_rows_32 = vpadd_u8(abs_row3_gt0, abs_row2_gt0); - uint8x8_t bitmap_rows_54 = vpadd_u8(abs_row5_gt0, abs_row4_gt0); - uint8x8_t bitmap_rows_76 = vpadd_u8(abs_row7_gt0, abs_row6_gt0); - uint8x8_t bitmap_rows_3210 = vpadd_u8(bitmap_rows_32, bitmap_rows_10); - uint8x8_t bitmap_rows_7654 = vpadd_u8(bitmap_rows_76, bitmap_rows_54); - uint8x8_t bitmap_all = vpadd_u8(bitmap_rows_7654, bitmap_rows_3210); + uint8x16_t bitmap_rows_3210 = vpaddq_u8(bitmap_rows_32, bitmap_rows_10); + uint8x16_t bitmap_rows_7654 = vpaddq_u8(bitmap_rows_76, bitmap_rows_54); + uint8x16_t bitmap_rows_76543210 = vpaddq_u8(bitmap_rows_7654, + bitmap_rows_3210); + uint8x8_t bitmap_all = vpadd_u8(vget_low_u8(bitmap_rows_76543210), + vget_high_u8(bitmap_rows_76543210)); /* Shift left to remove DC bit. */ bitmap_all = @@ -241,16 +211,16 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, /* Encode DC coefficient. */ + /* For negative coeffs: diff = abs(coeff) -1 = ~abs(coeff) */ + int16x8_t abs_row0 = vabsq_s16(row0); + int16x8_t row0_lz = vclzq_s16(abs_row0); + uint16x8_t row0_mask = vshlq_u16(vcltzq_s16(row0), vnegq_s16(row0_lz)); + uint16x8_t row0_diff = veorq_u16(vreinterpretq_u16_s16(abs_row0), row0_mask); /* Find nbits required to specify sign and amplitude of coefficient. */ -#if defined(_MSC_VER) && !defined(__clang__) - unsigned int lz = BUILTIN_CLZ(vgetq_lane_s16(abs_row0, 0)); -#else - unsigned int lz; - __asm__("clz %w0, %w1" : "=r"(lz) : "r"(vgetq_lane_s16(abs_row0, 0))); -#endif - unsigned int nbits = 32 - lz; + unsigned int lz = vgetq_lane_u16(vreinterpretq_u16_s16(row0_lz), 0); + unsigned int nbits = 16 - lz; /* Emit Huffman-coded symbol and additional diff bits. */ - unsigned int diff = (unsigned int)(vgetq_lane_u16(row0_diff, 0) << lz) >> lz; + unsigned int diff = vgetq_lane_u16(row0_diff, 0); PUT_CODE(dctbl->ehufco[nbits], dctbl->ehufsi[nbits], diff) /* Encode AC coefficients. */ @@ -263,13 +233,20 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, /* The most efficient method of computing nbits and diff depends on the * number of non-zero coefficients. If the bitmap is not too sparse (> 8 - * non-zero AC coefficients), it is beneficial to use Neon; else we compute - * nbits and diff on demand using scalar code. + * non-zero AC coefficients), it is beneficial to do all of the work using + * Neon; else we do some of the work using Neon and the rest on demand using + * scalar code. */ if (non_zero_coefficients > 8) { uint8_t block_nbits[DCTSIZE2]; - int16x8_t row0_lz = vclzq_s16(abs_row0); + int16x8_t abs_row1 = vabsq_s16(row1); + int16x8_t abs_row2 = vabsq_s16(row2); + int16x8_t abs_row3 = vabsq_s16(row3); + int16x8_t abs_row4 = vabsq_s16(row4); + int16x8_t abs_row5 = vabsq_s16(row5); + int16x8_t abs_row6 = vabsq_s16(row6); + int16x8_t abs_row7 = vabsq_s16(row7); int16x8_t row1_lz = vclzq_s16(abs_row1); int16x8_t row2_lz = vclzq_s16(abs_row2); int16x8_t row3_lz = vclzq_s16(abs_row3); @@ -277,49 +254,48 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, int16x8_t row5_lz = vclzq_s16(abs_row5); int16x8_t row6_lz = vclzq_s16(abs_row6); int16x8_t row7_lz = vclzq_s16(abs_row7); + /* Narrow leading zero count to 8 bits. */ + uint8x16_t row01_lz = vuzp1q_u8(vreinterpretq_u8_s16(row0_lz), + vreinterpretq_u8_s16(row1_lz)); + uint8x16_t row23_lz = vuzp1q_u8(vreinterpretq_u8_s16(row2_lz), + vreinterpretq_u8_s16(row3_lz)); + uint8x16_t row45_lz = vuzp1q_u8(vreinterpretq_u8_s16(row4_lz), + vreinterpretq_u8_s16(row5_lz)); + uint8x16_t row67_lz = vuzp1q_u8(vreinterpretq_u8_s16(row6_lz), + vreinterpretq_u8_s16(row7_lz)); /* Compute nbits needed to specify magnitude of each coefficient. */ - uint8x8_t row0_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row0_lz))); - uint8x8_t row1_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row1_lz))); - uint8x8_t row2_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row2_lz))); - uint8x8_t row3_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row3_lz))); - uint8x8_t row4_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row4_lz))); - uint8x8_t row5_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row5_lz))); - uint8x8_t row6_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row6_lz))); - uint8x8_t row7_nbits = vsub_u8(vdup_n_u8(16), - vmovn_u16(vreinterpretq_u16_s16(row7_lz))); + uint8x16_t row01_nbits = vsubq_u8(vdupq_n_u8(16), row01_lz); + uint8x16_t row23_nbits = vsubq_u8(vdupq_n_u8(16), row23_lz); + uint8x16_t row45_nbits = vsubq_u8(vdupq_n_u8(16), row45_lz); + uint8x16_t row67_nbits = vsubq_u8(vdupq_n_u8(16), row67_lz); /* Store nbits. */ - vst1_u8(block_nbits + 0 * DCTSIZE, row0_nbits); - vst1_u8(block_nbits + 1 * DCTSIZE, row1_nbits); - vst1_u8(block_nbits + 2 * DCTSIZE, row2_nbits); - vst1_u8(block_nbits + 3 * DCTSIZE, row3_nbits); - vst1_u8(block_nbits + 4 * DCTSIZE, row4_nbits); - vst1_u8(block_nbits + 5 * DCTSIZE, row5_nbits); - vst1_u8(block_nbits + 6 * DCTSIZE, row6_nbits); - vst1_u8(block_nbits + 7 * DCTSIZE, row7_nbits); + vst1q_u8(block_nbits + 0 * DCTSIZE, row01_nbits); + vst1q_u8(block_nbits + 2 * DCTSIZE, row23_nbits); + vst1q_u8(block_nbits + 4 * DCTSIZE, row45_nbits); + vst1q_u8(block_nbits + 6 * DCTSIZE, row67_nbits); /* Mask bits not required to specify sign and amplitude of diff. */ - row0_diff = vshlq_u16(row0_diff, row0_lz); - row1_diff = vshlq_u16(row1_diff, row1_lz); - row2_diff = vshlq_u16(row2_diff, row2_lz); - row3_diff = vshlq_u16(row3_diff, row3_lz); - row4_diff = vshlq_u16(row4_diff, row4_lz); - row5_diff = vshlq_u16(row5_diff, row5_lz); - row6_diff = vshlq_u16(row6_diff, row6_lz); - row7_diff = vshlq_u16(row7_diff, row7_lz); - row0_diff = vshlq_u16(row0_diff, vnegq_s16(row0_lz)); - row1_diff = vshlq_u16(row1_diff, vnegq_s16(row1_lz)); - row2_diff = vshlq_u16(row2_diff, vnegq_s16(row2_lz)); - row3_diff = vshlq_u16(row3_diff, vnegq_s16(row3_lz)); - row4_diff = vshlq_u16(row4_diff, vnegq_s16(row4_lz)); - row5_diff = vshlq_u16(row5_diff, vnegq_s16(row5_lz)); - row6_diff = vshlq_u16(row6_diff, vnegq_s16(row6_lz)); - row7_diff = vshlq_u16(row7_diff, vnegq_s16(row7_lz)); + uint16x8_t row1_mask = vshlq_u16(vcltzq_s16(row1), vnegq_s16(row1_lz)); + uint16x8_t row2_mask = vshlq_u16(vcltzq_s16(row2), vnegq_s16(row2_lz)); + uint16x8_t row3_mask = vshlq_u16(vcltzq_s16(row3), vnegq_s16(row3_lz)); + uint16x8_t row4_mask = vshlq_u16(vcltzq_s16(row4), vnegq_s16(row4_lz)); + uint16x8_t row5_mask = vshlq_u16(vcltzq_s16(row5), vnegq_s16(row5_lz)); + uint16x8_t row6_mask = vshlq_u16(vcltzq_s16(row6), vnegq_s16(row6_lz)); + uint16x8_t row7_mask = vshlq_u16(vcltzq_s16(row7), vnegq_s16(row7_lz)); + /* diff = abs(coeff) ^ sign(coeff) [no-op for positive coefficients] */ + uint16x8_t row1_diff = veorq_u16(vreinterpretq_u16_s16(abs_row1), + row1_mask); + uint16x8_t row2_diff = veorq_u16(vreinterpretq_u16_s16(abs_row2), + row2_mask); + uint16x8_t row3_diff = veorq_u16(vreinterpretq_u16_s16(abs_row3), + row3_mask); + uint16x8_t row4_diff = veorq_u16(vreinterpretq_u16_s16(abs_row4), + row4_mask); + uint16x8_t row5_diff = veorq_u16(vreinterpretq_u16_s16(abs_row5), + row5_mask); + uint16x8_t row6_diff = veorq_u16(vreinterpretq_u16_s16(abs_row6), + row6_mask); + uint16x8_t row7_diff = veorq_u16(vreinterpretq_u16_s16(abs_row7), + row7_mask); /* Store diff bits. */ vst1q_u16(block_diff + 0 * DCTSIZE, row0_diff); vst1q_u16(block_diff + 1 * DCTSIZE, row1_diff); @@ -349,7 +325,14 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, } } else if (bitmap != 0) { uint16_t block_abs[DCTSIZE2]; - /* Store absolute value of coefficients. */ + /* Compute and store absolute value of coefficients. */ + int16x8_t abs_row1 = vabsq_s16(row1); + int16x8_t abs_row2 = vabsq_s16(row2); + int16x8_t abs_row3 = vabsq_s16(row3); + int16x8_t abs_row4 = vabsq_s16(row4); + int16x8_t abs_row5 = vabsq_s16(row5); + int16x8_t abs_row6 = vabsq_s16(row6); + int16x8_t abs_row7 = vabsq_s16(row7); vst1q_u16(block_abs + 0 * DCTSIZE, vreinterpretq_u16_s16(abs_row0)); vst1q_u16(block_abs + 1 * DCTSIZE, vreinterpretq_u16_s16(abs_row1)); vst1q_u16(block_abs + 2 * DCTSIZE, vreinterpretq_u16_s16(abs_row2)); @@ -358,7 +341,21 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, vst1q_u16(block_abs + 5 * DCTSIZE, vreinterpretq_u16_s16(abs_row5)); vst1q_u16(block_abs + 6 * DCTSIZE, vreinterpretq_u16_s16(abs_row6)); vst1q_u16(block_abs + 7 * DCTSIZE, vreinterpretq_u16_s16(abs_row7)); - /* Store diff bits. */ + /* Compute diff bits (without nbits mask) and store. */ + uint16x8_t row1_diff = veorq_u16(vreinterpretq_u16_s16(abs_row1), + vcltzq_s16(row1)); + uint16x8_t row2_diff = veorq_u16(vreinterpretq_u16_s16(abs_row2), + vcltzq_s16(row2)); + uint16x8_t row3_diff = veorq_u16(vreinterpretq_u16_s16(abs_row3), + vcltzq_s16(row3)); + uint16x8_t row4_diff = veorq_u16(vreinterpretq_u16_s16(abs_row4), + vcltzq_s16(row4)); + uint16x8_t row5_diff = veorq_u16(vreinterpretq_u16_s16(abs_row5), + vcltzq_s16(row5)); + uint16x8_t row6_diff = veorq_u16(vreinterpretq_u16_s16(abs_row6), + vcltzq_s16(row6)); + uint16x8_t row7_diff = veorq_u16(vreinterpretq_u16_s16(abs_row7), + vcltzq_s16(row7)); vst1q_u16(block_diff + 0 * DCTSIZE, row0_diff); vst1q_u16(block_diff + 1 * DCTSIZE, row1_diff); vst1q_u16(block_diff + 2 * DCTSIZE, row2_diff); From 98bc3eeb3abce0424f7063ecce06d214256015a5 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 24 Feb 2022 23:09:58 -0600 Subject: [PATCH 55/56] Neon/AArch64: Fix/suppress UBSan warnings - Suppress a UBSan warning regarding storing a 64-bit value to a non-64-bit-aligned address. That behavior is technically undefined per the C spec but is supported in the context of the AArch64 architecture and compilers. - Explicitly promote block_diff[i] to unsigned int prior to left shifting it, in order to avoid a UBSan warning. This warning also described behavior that is technically undefined per the C spec but is supported in the context of the AArch64 architecture and compilers. Changing the type cast order eliminated the warning without changing the generated assembly code. Closes #582 --- simd/arm/aarch64/jchuff-neon.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/simd/arm/aarch64/jchuff-neon.c b/simd/arm/aarch64/jchuff-neon.c index e7c52bc0..607a1160 100644 --- a/simd/arm/aarch64/jchuff-neon.c +++ b/simd/arm/aarch64/jchuff-neon.c @@ -2,7 +2,7 @@ * jchuff-neon.c - Huffman entropy encoding (64-bit Arm Neon) * * Copyright (C) 2020-2021, Arm Limited. All Rights Reserved. - * Copyright (C) 2020, D. R. Commander. All Rights Reserved. + * Copyright (C) 2020, 2022, D. R. Commander. All Rights Reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -59,6 +59,17 @@ ALIGN(16) static const uint8_t jsimd_huff_encode_one_block_consts[] = { 14, 15, 30, 31, 44, 45, 46, 47 }; +/* The AArch64 implementation of the FLUSH() macro triggers a UBSan misaligned + * address warning because the macro sometimes writes a 64-bit value to a + * non-64-bit-aligned address. That behavior is technically undefined per + * the C specification, but it is supported by the AArch64 architecture and + * compilers. + */ +#if defined(__has_feature) +#if __has_feature(undefined_behavior_sanitizer) +__attribute__((no_sanitize("alignment"))) +#endif +#endif JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, JCOEFPTR block, int last_dc_val, c_derived_tbl *dctbl, @@ -372,7 +383,7 @@ JOCTET *jsimd_huff_encode_one_block_neon(void *state, JOCTET *buffer, bitmap <<= r; lz = BUILTIN_CLZ(block_abs[i]); nbits = 32 - lz; - diff = (unsigned int)(block_diff[i] << lz) >> lz; + diff = ((unsigned int)block_diff[i] << lz) >> lz; while (r > 15) { /* If run length > 15, emit special run-length-16 codes. */ PUT_BITS(code_0xf0, size_0xf0) From c5f269eb9665435271c05fbcaf8721fa58e9eafa Mon Sep 17 00:00:00 2001 From: Jonathan Wright Date: Fri, 3 Sep 2021 11:52:40 +0100 Subject: [PATCH 56/56] Neon/AArch64: Explicitly unroll quant loop w/Clang The loop in jsimd_quantize_neon() is only executed twice and should be unrolled for AArch64 targets. GCC does that by default, but Clang 11 and later versions available at the time of this writing do not. This patch adds an unroll pragma when targetting AArch64 with Clang. We do not use the unroll pragma for AArch32 targets, because it causes the Clang-generated assembly code to exhaust the available Neon registers (32 x 64-bit) and spill to the stack. (DRC: Referring to the discussion in #570, this is likely due to compiler confusion that results in poor register allocation. It is possible to eliminate the spillage and reduce the instruction count by loading the data on a just-in-time basis, thus explicitly interleaving compute and I/O, but the performance implications of that are currently unknown.) The effects of unrolling the quantization loop are: 1) elimination of the loop control flow overhead and 2) enabling the use of LDP/STP instructions that work from a single base pointer, instead of using double the number of LDR/STR instructions, each requiring an address calculation. Closes #570 --- simd/arm/jquanti-neon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/simd/arm/jquanti-neon.c b/simd/arm/jquanti-neon.c index a7eb6f19..d5d95d89 100644 --- a/simd/arm/jquanti-neon.c +++ b/simd/arm/jquanti-neon.c @@ -1,7 +1,7 @@ /* * jquanti-neon.c - sample data conversion and quantization (Arm Neon) * - * Copyright (C) 2020, Arm Limited. All Rights Reserved. + * Copyright (C) 2020-2021, Arm Limited. All Rights Reserved. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -100,6 +100,9 @@ void jsimd_quantize_neon(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *shift_ptr = divisors + 3 * DCTSIZE2; int i; +#if defined(__clang__) && (defined(__aarch64__) || defined(_M_ARM64)) +#pragma unroll +#endif for (i = 0; i < DCTSIZE; i += DCTSIZE / 2) { /* Load DCT coefficients. */ int16x8_t row0 = vld1q_s16(workspace + (i + 0) * DCTSIZE);