diff -Nru libdeflate-1.5/.cirrus.yml libdeflate-1.6/.cirrus.yml --- libdeflate-1.5/.cirrus.yml 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/.cirrus.yml 2020-05-13 02:42:04.000000000 +0000 @@ -1,8 +1,8 @@ task: freebsd_instance: matrix: - - image: freebsd-11-2-release-amd64 - - image: freebsd-12-0-release-amd64 + - image_family: freebsd-11-3-snap + - image_family: freebsd-12-1-snap install_script: pkg install -y gmake script: - gmake check diff -Nru libdeflate-1.5/common/common_defs.h libdeflate-1.6/common/common_defs.h --- libdeflate-1.5/common/common_defs.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/common/common_defs.h 2020-05-13 02:42:04.000000000 +0000 @@ -47,9 +47,7 @@ #endif /* Fixed-width integer types */ -#ifndef PRIu32 -# include -#endif +#include typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; @@ -246,39 +244,6 @@ # define UNALIGNED_ACCESS_IS_FAST 0 #endif -/* - * DEFINE_UNALIGNED_TYPE(type) - a macro that, given an integer type 'type', - * defines load_type_unaligned(addr) and store_type_unaligned(v, addr) functions - * which load and store variables of type 'type' from/to unaligned memory - * addresses. If not defined, a fallback is used. - */ -#ifndef DEFINE_UNALIGNED_TYPE - -/* - * Although memcpy() may seem inefficient, it *usually* gets optimized - * appropriately by modern compilers. It's portable and may be the best we can - * do for a fallback... - */ -#include - -#define DEFINE_UNALIGNED_TYPE(type) \ - \ -static forceinline type \ -load_##type##_unaligned(const void *p) \ -{ \ - type v; \ - memcpy(&v, p, sizeof(v)); \ - return v; \ -} \ - \ -static forceinline void \ -store_##type##_unaligned(type v, void *p) \ -{ \ - memcpy(p, &v, sizeof(v)); \ -} - -#endif /* !DEFINE_UNALIGNED_TYPE */ - /* ========================================================================== */ /* Bit scan functions */ /* ========================================================================== */ diff -Nru libdeflate-1.5/common/compiler_gcc.h libdeflate-1.6/common/compiler_gcc.h --- libdeflate-1.5/common/compiler_gcc.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/common/compiler_gcc.h 2020-05-13 02:42:04.000000000 +0000 @@ -134,25 +134,6 @@ # define UNALIGNED_ACCESS_IS_FAST 1 #endif -/* With gcc, we can access unaligned memory through 'packed' structures. */ -#define DEFINE_UNALIGNED_TYPE(type) \ - \ -struct type##unaligned { \ - type v; \ -} __attribute__((packed)); \ - \ -static forceinline type \ -load_##type##_unaligned(const void *p) \ -{ \ - return ((const struct type##unaligned *)p)->v; \ -} \ - \ -static forceinline void \ -store_##type##_unaligned(type v, void *p) \ -{ \ - ((struct type##unaligned *)p)->v = v; \ -} - #define bsr32(n) (31 - __builtin_clz(n)) #define bsr64(n) (63 - __builtin_clzll(n)) #define bsf32(n) __builtin_ctz(n) diff -Nru libdeflate-1.5/common/compiler_msc.h libdeflate-1.6/common/compiler_msc.h --- libdeflate-1.5/common/compiler_msc.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/common/compiler_msc.h 2020-05-13 02:42:04.000000000 +0000 @@ -2,6 +2,9 @@ * compiler_msc.h - definitions for the Microsoft C Compiler */ +#include +#include /* for _byteswap_*() */ + #define LIBEXPORT __declspec(dllexport) /* @@ -22,24 +25,6 @@ typedef int ssize_t; #endif -/* - * Old versions (e.g. VS2010) of MSC have stdint.h but not the C99 header - * inttypes.h. Work around this by defining the PRI* macros ourselves. - */ -#include -#define PRIu8 "hhu" -#define PRIu16 "hu" -#define PRIu32 "u" -#define PRIu64 "llu" -#define PRIi8 "hhi" -#define PRIi16 "hi" -#define PRIi32 "i" -#define PRIi64 "lli" -#define PRIx8 "hhx" -#define PRIx16 "hx" -#define PRIx32 "x" -#define PRIx64 "llx" - /* Assume a little endian architecture with fast unaligned access */ #define CPU_IS_LITTLE_ENDIAN() 1 #define UNALIGNED_ACCESS_IS_FAST 1 @@ -52,7 +37,6 @@ #define forceinline __forceinline /* Byte swap functions */ -#include #define bswap16 _byteswap_ushort #define bswap32 _byteswap_ulong #define bswap64 _byteswap_uint64 diff -Nru libdeflate-1.5/debian/changelog libdeflate-1.6/debian/changelog --- libdeflate-1.5/debian/changelog 2020-02-12 17:04:25.000000000 +0000 +++ libdeflate-1.6/debian/changelog 2020-05-13 10:04:06.000000000 +0000 @@ -1,3 +1,16 @@ +libdeflate (1.6-1) unstable; urgency=medium + + * New upstream version + * Add salsa-ci file (routine-update) + * Rules-Requires-Root: no (routine-update) + * Wrap long lines in changelog entries: 1.3-2. + * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository, + Repository-Browse. + * Add new symbols + * Mark libdeflate0 at Multi-Arch: same + + -- Michael R. Crusoe Wed, 13 May 2020 12:04:06 +0200 + libdeflate (1.5-3) unstable; urgency=medium * Source only upload @@ -32,7 +45,8 @@ libdeflate (1.3-2) unstable; urgency=medium - * add patch from upstream: test_slow_decompression: skip by default since it's flaky + * add patch from upstream: test_slow_decompression: skip by default since it's + flaky Should fix build on ppc64el -- Michael R. Crusoe Fri, 13 Sep 2019 13:24:25 +0200 diff -Nru libdeflate-1.5/debian/control libdeflate-1.6/debian/control --- libdeflate-1.5/debian/control 2020-02-10 12:02:34.000000000 +0000 +++ libdeflate-1.6/debian/control 2020-05-13 10:04:06.000000000 +0000 @@ -12,8 +12,10 @@ Vcs-Browser: https://salsa.debian.org/med-team/libdeflate Vcs-Git: https://salsa.debian.org/med-team/libdeflate.git Homepage: https://github.com/ebiggers/libdeflate +Rules-Requires-Root: no Package: libdeflate0 +Multi-Arch: same Architecture: any Section: libs Depends: ${shlibs:Depends}, diff -Nru libdeflate-1.5/debian/libdeflate0.symbols libdeflate-1.6/debian/libdeflate0.symbols --- libdeflate-1.5/debian/libdeflate0.symbols 2019-08-23 10:27:00.000000000 +0000 +++ libdeflate-1.6/debian/libdeflate0.symbols 2020-05-13 10:04:06.000000000 +0000 @@ -14,6 +14,8 @@ libdeflate_gzip_compress_bound@Base 1.0 libdeflate_gzip_decompress@Base 1.0 libdeflate_gzip_decompress_ex@Base 1.0 + libdeflate_set_memory_allocator@Base 1.6 libdeflate_zlib_compress@Base 1.0 libdeflate_zlib_compress_bound@Base 1.0 libdeflate_zlib_decompress@Base 1.0 + libdeflate_zlib_decompress_ex@Base 1.6 diff -Nru libdeflate-1.5/debian/salsa-ci.yml libdeflate-1.6/debian/salsa-ci.yml --- libdeflate-1.5/debian/salsa-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ libdeflate-1.6/debian/salsa-ci.yml 2020-05-13 10:03:59.000000000 +0000 @@ -0,0 +1,4 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff -Nru libdeflate-1.5/debian/upstream/metadata libdeflate-1.6/debian/upstream/metadata --- libdeflate-1.5/debian/upstream/metadata 1970-01-01 00:00:00.000000000 +0000 +++ libdeflate-1.6/debian/upstream/metadata 2020-05-13 10:04:06.000000000 +0000 @@ -0,0 +1,5 @@ +--- +Bug-Database: https://github.com/ebiggers/libdeflate/issues +Bug-Submit: https://github.com/ebiggers/libdeflate/issues/new +Repository: https://github.com/ebiggers/libdeflate.git +Repository-Browse: https://github.com/ebiggers/libdeflate diff -Nru libdeflate-1.5/.gitignore libdeflate-1.6/.gitignore --- libdeflate-1.5/.gitignore 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/.gitignore 2020-05-13 02:42:04.000000000 +0000 @@ -1,6 +1,7 @@ *.a *.def *.dll +*.dllobj *.dylib *.exe *.exp diff -Nru libdeflate-1.5/lib/aligned_malloc.c libdeflate-1.6/lib/aligned_malloc.c --- libdeflate-1.5/lib/aligned_malloc.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/aligned_malloc.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,57 +0,0 @@ -/* - * aligned_malloc.c - aligned memory allocation - * - * Originally public domain; changes after 2016-09-07 are copyrighted. - * - * Copyright 2016 Eric Biggers - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/* - * This file provides portable aligned memory allocation functions that only - * use malloc() and free(). This avoids portability problems with - * posix_memalign(), aligned_alloc(), etc. - */ - -#include - -#include "aligned_malloc.h" - -void * -aligned_malloc(size_t alignment, size_t size) -{ - void *ptr = malloc(sizeof(void *) + alignment - 1 + size); - if (ptr) { - void *orig_ptr = ptr; - ptr = (void *)ALIGN((uintptr_t)ptr + sizeof(void *), alignment); - ((void **)ptr)[-1] = orig_ptr; - } - return ptr; -} - -void -aligned_free(void *ptr) -{ - if (ptr) - free(((void **)ptr)[-1]); -} diff -Nru libdeflate-1.5/lib/aligned_malloc.h libdeflate-1.6/lib/aligned_malloc.h --- libdeflate-1.5/lib/aligned_malloc.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/aligned_malloc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -/* - * aligned_malloc.c - aligned memory allocation - */ - -#ifndef LIB_ALIGNED_MALLOC_H -#define LIB_ALIGNED_MALLOC_H - -#include "lib_common.h" - -extern void *aligned_malloc(size_t alignment, size_t size); -extern void aligned_free(void *ptr); - -#endif /* LIB_ALIGNED_MALLOC_H */ diff -Nru libdeflate-1.5/lib/arm/cpu_features.h libdeflate-1.6/lib/arm/cpu_features.h --- libdeflate-1.5/lib/arm/cpu_features.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/arm/cpu_features.h 2020-05-13 02:42:04.000000000 +0000 @@ -8,7 +8,9 @@ #include "../lib_common.h" #if (defined(__arm__) || defined(__aarch64__)) && \ - defined(__linux__) && COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE + defined(__linux__) && \ + COMPILER_SUPPORTS_TARGET_FUNCTION_ATTRIBUTE && \ + !defined(FREESTANDING) # define ARM_CPU_FEATURES_ENABLED 1 #else # define ARM_CPU_FEATURES_ENABLED 0 @@ -23,7 +25,7 @@ extern volatile u32 _cpu_features; -extern void setup_cpu_features(void); +void setup_cpu_features(void); static inline u32 get_cpu_features(void) { diff -Nru libdeflate-1.5/lib/deflate_compress.c libdeflate-1.6/lib/deflate_compress.c --- libdeflate-1.5/lib/deflate_compress.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/deflate_compress.c 2020-05-13 02:42:04.000000000 +0000 @@ -27,10 +27,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include - -#include "aligned_malloc.h" #include "deflate_compress.h" #include "deflate_constants.h" #include "unaligned.h" @@ -2682,7 +2678,7 @@ #endif size = offsetof(struct libdeflate_compressor, p) + sizeof(c->p.g); - c = aligned_malloc(MATCHFINDER_ALIGNMENT, size); + c = libdeflate_aligned_malloc(MATCHFINDER_ALIGNMENT, size); if (!c) return NULL; @@ -2766,7 +2762,7 @@ break; #endif default: - aligned_free(c); + libdeflate_aligned_free(c); return NULL; } @@ -2802,7 +2798,7 @@ LIBDEFLATEEXPORT void LIBDEFLATEAPI libdeflate_free_compressor(struct libdeflate_compressor *c) { - aligned_free(c); + libdeflate_aligned_free(c); } unsigned int diff -Nru libdeflate-1.5/lib/deflate_compress.h libdeflate-1.6/lib/deflate_compress.h --- libdeflate-1.5/lib/deflate_compress.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/deflate_compress.h 2020-05-13 02:42:04.000000000 +0000 @@ -8,7 +8,6 @@ struct libdeflate_compressor; -extern unsigned int -deflate_get_compression_level(struct libdeflate_compressor *c); +unsigned int deflate_get_compression_level(struct libdeflate_compressor *c); #endif /* LIB_DEFLATE_COMPRESS_H */ diff -Nru libdeflate-1.5/lib/deflate_decompress.c libdeflate-1.6/lib/deflate_decompress.c --- libdeflate-1.5/lib/deflate_decompress.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/deflate_decompress.c 2020-05-13 02:42:04.000000000 +0000 @@ -45,8 +45,6 @@ */ #include -#include -#include #include "deflate_constants.h" #include "unaligned.h" @@ -987,11 +985,16 @@ * * But for simplicity, we currently just zero the whole decompressor. */ - return calloc(1, sizeof(struct libdeflate_decompressor)); + struct libdeflate_decompressor *d = libdeflate_malloc(sizeof(*d)); + + if (d == NULL) + return NULL; + memset(d, 0, sizeof(*d)); + return d; } LIBDEFLATEEXPORT void LIBDEFLATEAPI libdeflate_free_decompressor(struct libdeflate_decompressor *d) { - free(d); + libdeflate_free(d); } diff -Nru libdeflate-1.5/lib/gzip_compress.c libdeflate-1.6/lib/gzip_compress.c --- libdeflate-1.5/lib/gzip_compress.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/gzip_compress.c 2020-05-13 02:42:04.000000000 +0000 @@ -35,7 +35,7 @@ LIBDEFLATEEXPORT size_t LIBDEFLATEAPI libdeflate_gzip_compress(struct libdeflate_compressor *c, - const void *in, size_t in_size, + const void *in, size_t in_nbytes, void *out, size_t out_nbytes_avail) { u8 *out_next = out; @@ -61,26 +61,26 @@ xfl = 0; compression_level = deflate_get_compression_level(c); if (compression_level < 2) - xfl |= GZIP_XFL_FASTEST_COMRESSION; + xfl |= GZIP_XFL_FASTEST_COMPRESSION; else if (compression_level >= 8) - xfl |= GZIP_XFL_SLOWEST_COMRESSION; + xfl |= GZIP_XFL_SLOWEST_COMPRESSION; *out_next++ = xfl; /* OS */ *out_next++ = GZIP_OS_UNKNOWN; /* OS */ /* Compressed data */ - deflate_size = libdeflate_deflate_compress(c, in, in_size, out_next, + deflate_size = libdeflate_deflate_compress(c, in, in_nbytes, out_next, out_nbytes_avail - GZIP_MIN_OVERHEAD); if (deflate_size == 0) return 0; out_next += deflate_size; /* CRC32 */ - put_unaligned_le32(libdeflate_crc32(0, in, in_size), out_next); + put_unaligned_le32(libdeflate_crc32(0, in, in_nbytes), out_next); out_next += 4; /* ISIZE */ - put_unaligned_le32((u32)in_size, out_next); + put_unaligned_le32((u32)in_nbytes, out_next); out_next += 4; return out_next - (u8 *)out; diff -Nru libdeflate-1.5/lib/gzip_constants.h libdeflate-1.6/lib/gzip_constants.h --- libdeflate-1.5/lib/gzip_constants.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/gzip_constants.h 2020-05-13 02:42:04.000000000 +0000 @@ -23,8 +23,8 @@ #define GZIP_MTIME_UNAVAILABLE 0 -#define GZIP_XFL_SLOWEST_COMRESSION 0x02 -#define GZIP_XFL_FASTEST_COMRESSION 0x04 +#define GZIP_XFL_SLOWEST_COMPRESSION 0x02 +#define GZIP_XFL_FASTEST_COMPRESSION 0x04 #define GZIP_OS_FAT 0 #define GZIP_OS_AMIGA 1 diff -Nru libdeflate-1.5/lib/lib_common.h libdeflate-1.6/lib/lib_common.h --- libdeflate-1.5/lib/lib_common.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/lib_common.h 2020-05-13 02:42:04.000000000 +0000 @@ -12,12 +12,12 @@ #define BUILDING_LIBDEFLATE -#include "common_defs.h" +#include "../common/common_defs.h" /* - * Prefix with "_libdeflate_" all global symbols which are not part of the API. - * This avoids exposing overly generic names when libdeflate is built as a - * static library. + * Prefix with "_libdeflate_" all global symbols which are not part of the API + * and don't already have a "libdeflate" prefix. This avoids exposing overly + * generic names when libdeflate is built as a static library. * * Note that the chosen prefix is not really important and can be changed * without breaking library users. It was just chosen so that the resulting @@ -26,10 +26,42 @@ * shared library, since these symbols are not exported. */ #define SYM_FIXUP(sym) _libdeflate_##sym -#define aligned_malloc SYM_FIXUP(aligned_malloc) -#define aligned_free SYM_FIXUP(aligned_free) #define deflate_get_compression_level SYM_FIXUP(deflate_get_compression_level) #define _cpu_features SYM_FIXUP(_cpu_features) #define setup_cpu_features SYM_FIXUP(setup_cpu_features) +void *libdeflate_malloc(size_t size); +void libdeflate_free(void *ptr); + +void *libdeflate_aligned_malloc(size_t alignment, size_t size); +void libdeflate_aligned_free(void *ptr); + +#ifdef FREESTANDING +/* + * With -ffreestanding, may be missing, and we must provide + * implementations of memset(), memcpy(), memmove(), and memcmp(). + * See https://gcc.gnu.org/onlinedocs/gcc/Standards.html + * + * Also, -ffreestanding disables interpreting calls to these functions as + * built-ins. E.g., calling memcpy(&v, p, WORDBYTES) will make a function call, + * not be optimized to a single load instruction. For performance reasons we + * don't want that. So, declare these functions as macros that expand to the + * corresponding built-ins. This approach is recommended in the gcc man page. + * We still need the actual function definitions in case gcc calls them. + */ +void *memset(void *s, int c, size_t n); +#define memset(s, c, n) __builtin_memset((s), (c), (n)) + +void *memcpy(void *dest, const void *src, size_t n); +#define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) + +void *memmove(void *dest, const void *src, size_t n); +#define memmove(dest, src, n) __builtin_memmove((dest), (src), (n)) + +int memcmp(const void *s1, const void *s2, size_t n); +#define memcmp(s1, s2, n) __builtin_memcmp((s1), (s2), (n)) +#else +#include +#endif + #endif /* LIB_LIB_COMMON_H */ diff -Nru libdeflate-1.5/lib/unaligned.h libdeflate-1.6/lib/unaligned.h --- libdeflate-1.5/lib/unaligned.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/unaligned.h 2020-05-13 02:42:04.000000000 +0000 @@ -7,13 +7,39 @@ #include "lib_common.h" +/***** Unaligned loads and stores without endianness conversion *****/ + /* - * Naming note: + * memcpy() is portable, and it usually gets optimized appropriately by modern + * compilers. I.e., each memcpy() of 1, 2, 4, or WORDBYTES bytes gets compiled + * to a load or store instruction, not to an actual function call. + * + * We no longer use the "packed struct" approach, as that is nonstandard, has + * unclear semantics, and doesn't receive enough testing + * (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94994). * - * {load,store}_*_unaligned() deal with raw bytes without endianness conversion. - * {get,put}_unaligned_*() deal with a specific endianness. + * arm32 with __ARM_FEATURE_UNALIGNED in gcc 5 and earlier is a known exception + * where memcpy() generates inefficient code + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67366). However, we no longer + * consider that one case important enough to maintain different code for. + * If you run into it, please just use a newer version of gcc (or use clang). */ +#define DEFINE_UNALIGNED_TYPE(type) \ +static forceinline type \ +load_##type##_unaligned(const void *p) \ +{ \ + type v; \ + memcpy(&v, p, sizeof(v)); \ + return v; \ +} \ + \ +static forceinline void \ +store_##type##_unaligned(type v, void *p) \ +{ \ + memcpy(p, &v, sizeof(v)); \ +} + DEFINE_UNALIGNED_TYPE(u16) DEFINE_UNALIGNED_TYPE(u32) DEFINE_UNALIGNED_TYPE(u64) @@ -22,7 +48,7 @@ #define load_word_unaligned load_machine_word_t_unaligned #define store_word_unaligned store_machine_word_t_unaligned -/***** Unaligned loads *****/ +/***** Unaligned loads with endianness conversion *****/ static forceinline u16 get_unaligned_le16(const u8 *p) @@ -84,7 +110,7 @@ return get_unaligned_le64(p); } -/***** Unaligned stores *****/ +/***** Unaligned stores with endianness conversion *****/ static forceinline void put_unaligned_le16(u16 v, u8 *p) diff -Nru libdeflate-1.5/lib/utils.c libdeflate-1.6/lib/utils.c --- libdeflate-1.5/lib/utils.c 1970-01-01 00:00:00.000000000 +0000 +++ libdeflate-1.6/lib/utils.c 2020-05-13 02:42:04.000000000 +0000 @@ -0,0 +1,138 @@ +/* + * utils.c - utility functions for libdeflate + * + * Copyright 2016 Eric Biggers + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifdef FREESTANDING +# define malloc NULL +# define free NULL +#else +# include +#endif + +#include "lib_common.h" + +#include "libdeflate.h" + +static void *(*libdeflate_malloc_func)(size_t) = malloc; +static void (*libdeflate_free_func)(void *) = free; + +void * +libdeflate_malloc(size_t size) +{ + return (*libdeflate_malloc_func)(size); +} + +void +libdeflate_free(void *ptr) +{ + (*libdeflate_free_func)(ptr); +} + +void * +libdeflate_aligned_malloc(size_t alignment, size_t size) +{ + void *ptr = libdeflate_malloc(sizeof(void *) + alignment - 1 + size); + if (ptr) { + void *orig_ptr = ptr; + ptr = (void *)ALIGN((uintptr_t)ptr + sizeof(void *), alignment); + ((void **)ptr)[-1] = orig_ptr; + } + return ptr; +} + +void +libdeflate_aligned_free(void *ptr) +{ + if (ptr) + libdeflate_free(((void **)ptr)[-1]); +} + +LIBDEFLATEEXPORT void LIBDEFLATEAPI +libdeflate_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *)) +{ + libdeflate_malloc_func = malloc_func; + libdeflate_free_func = free_func; +} + +/* + * Implementations of libc functions for freestanding library builds. + * Normal library builds don't use these. Not optimized yet; usually the + * compiler expands these functions and doesn't actually call them anyway. + */ +#ifdef FREESTANDING +#undef memset +void *memset(void *s, int c, size_t n) +{ + u8 *p = s; + size_t i; + + for (i = 0; i < n; i++) + p[i] = c; + return s; +} + +#undef memcpy +void *memcpy(void *dest, const void *src, size_t n) +{ + u8 *d = dest; + const u8 *s = src; + size_t i; + + for (i = 0; i < n; i++) + d[i] = s[i]; + return dest; +} + +#undef memmove +void *memmove(void *dest, const void *src, size_t n) +{ + u8 *d = dest; + const u8 *s = src; + size_t i; + + if (d <= s) + return memcpy(d, s, n); + + for (i = n; i > 0; i--) + d[i - 1] = s[i - 1]; + return dest; +} + +#undef memcmp +int memcmp(const void *s1, const void *s2, size_t n) +{ + const u8 *p1 = s1; + const u8 *p2 = s2; + size_t i; + + for (i = 0; i < n; i++) { + if (p1[i] != p2[i]) + return (int)p1[i] - (int)p2[i]; + } + return 0; +} +#endif /* FREESTANDING */ diff -Nru libdeflate-1.5/lib/x86/cpu_features.h libdeflate-1.6/lib/x86/cpu_features.h --- libdeflate-1.5/lib/x86/cpu_features.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/x86/cpu_features.h 2020-05-13 02:42:04.000000000 +0000 @@ -27,7 +27,7 @@ extern volatile u32 _cpu_features; -extern void setup_cpu_features(void); +void setup_cpu_features(void); static inline u32 get_cpu_features(void) { diff -Nru libdeflate-1.5/lib/zlib_compress.c libdeflate-1.6/lib/zlib_compress.c --- libdeflate-1.5/lib/zlib_compress.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/zlib_compress.c 2020-05-13 02:42:04.000000000 +0000 @@ -35,7 +35,7 @@ LIBDEFLATEEXPORT size_t LIBDEFLATEAPI libdeflate_zlib_compress(struct libdeflate_compressor *c, - const void *in, size_t in_size, + const void *in, size_t in_nbytes, void *out, size_t out_nbytes_avail) { u8 *out_next = out; @@ -65,14 +65,14 @@ out_next += 2; /* Compressed data */ - deflate_size = libdeflate_deflate_compress(c, in, in_size, out_next, + deflate_size = libdeflate_deflate_compress(c, in, in_nbytes, out_next, out_nbytes_avail - ZLIB_MIN_OVERHEAD); if (deflate_size == 0) return 0; out_next += deflate_size; /* ADLER32 */ - put_unaligned_be32(libdeflate_adler32(1, in, in_size), out_next); + put_unaligned_be32(libdeflate_adler32(1, in, in_nbytes), out_next); out_next += 4; return out_next - (u8 *)out; diff -Nru libdeflate-1.5/lib/zlib_decompress.c libdeflate-1.6/lib/zlib_decompress.c --- libdeflate-1.5/lib/zlib_decompress.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/lib/zlib_decompress.c 2020-05-13 02:42:04.000000000 +0000 @@ -33,14 +33,16 @@ #include "libdeflate.h" LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI -libdeflate_zlib_decompress(struct libdeflate_decompressor *d, - const void *in, size_t in_nbytes, - void *out, size_t out_nbytes_avail, - size_t *actual_out_nbytes_ret) +libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *d, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_in_nbytes_ret, + size_t *actual_out_nbytes_ret) { const u8 *in_next = in; const u8 * const in_end = in_next + in_nbytes; u16 hdr; + size_t actual_in_nbytes; size_t actual_out_nbytes; enum libdeflate_result result; @@ -68,10 +70,10 @@ return LIBDEFLATE_BAD_DATA; /* Compressed data */ - result = libdeflate_deflate_decompress(d, in_next, + result = libdeflate_deflate_decompress_ex(d, in_next, in_end - ZLIB_FOOTER_SIZE - in_next, out, out_nbytes_avail, - actual_out_nbytes_ret); + &actual_in_nbytes, actual_out_nbytes_ret); if (result != LIBDEFLATE_SUCCESS) return result; @@ -80,12 +82,27 @@ else actual_out_nbytes = out_nbytes_avail; - in_next = in_end - ZLIB_FOOTER_SIZE; + in_next += actual_in_nbytes; /* ADLER32 */ if (libdeflate_adler32(1, out, actual_out_nbytes) != get_unaligned_be32(in_next)) return LIBDEFLATE_BAD_DATA; + in_next += 4; + + if (actual_in_nbytes_ret) + *actual_in_nbytes_ret = in_next - (u8 *)in; return LIBDEFLATE_SUCCESS; } + +LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI +libdeflate_zlib_decompress(struct libdeflate_decompressor *d, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_out_nbytes_ret) +{ + return libdeflate_zlib_decompress_ex(d, in, in_nbytes, + out, out_nbytes_avail, + NULL, actual_out_nbytes_ret); +} diff -Nru libdeflate-1.5/libdeflate.h libdeflate-1.6/libdeflate.h --- libdeflate-1.5/libdeflate.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/libdeflate.h 2020-05-13 02:42:04.000000000 +0000 @@ -10,8 +10,8 @@ #endif #define LIBDEFLATE_VERSION_MAJOR 1 -#define LIBDEFLATE_VERSION_MINOR 5 -#define LIBDEFLATE_VERSION_STRING "1.5" +#define LIBDEFLATE_VERSION_MINOR 6 +#define LIBDEFLATE_VERSION_STRING "1.6" #include #include @@ -255,6 +255,10 @@ /* * Like libdeflate_deflate_decompress(), but assumes the zlib wrapper format * instead of raw DEFLATE. + * + * Decompression will stop at the end of the zlib stream, even if it is shorter + * than 'in_nbytes'. If you need to know exactly where the zlib stream ended, + * use libdeflate_zlib_decompress_ex(). */ LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI libdeflate_zlib_decompress(struct libdeflate_decompressor *decompressor, @@ -263,6 +267,20 @@ size_t *actual_out_nbytes_ret); /* + * Like libdeflate_zlib_decompress(), but adds the 'actual_in_nbytes_ret' + * argument. If 'actual_in_nbytes_ret' is not NULL and the decompression + * succeeds (indicating that the first zlib-compressed stream in the input + * buffer was decompressed), then the actual number of input bytes consumed is + * written to *actual_in_nbytes_ret. + */ +LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI +libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *decompressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_in_nbytes_ret, + size_t *actual_out_nbytes_ret); + +/* * Like libdeflate_deflate_decompress(), but assumes the gzip wrapper format * instead of raw DEFLATE. * @@ -321,6 +339,22 @@ LIBDEFLATEEXPORT uint32_t LIBDEFLATEAPI libdeflate_crc32(uint32_t crc, const void *buffer, size_t len); +/* ========================================================================== */ +/* Custom memory allocator */ +/* ========================================================================== */ + +/* + * Install a custom memory allocator which libdeflate will use for all memory + * allocations. 'malloc_func' is a function that must behave like malloc(), and + * 'free_func' is a function that must behave like free(). + * + * There must not be any libdeflate_compressor or libdeflate_decompressor + * structures in existence when calling this function. + */ +LIBDEFLATEEXPORT void LIBDEFLATEAPI +libdeflate_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *)); + #ifdef __cplusplus } #endif diff -Nru libdeflate-1.5/Makefile libdeflate-1.6/Makefile --- libdeflate-1.5/Makefile 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/Makefile 2020-05-13 02:42:04.000000000 +0000 @@ -26,6 +26,10 @@ # Define DESTDIR to override the installation destination directory # (default: empty string) # +# Define FREESTANDING to build a freestanding library, i.e. a library that +# doesn't link to any libc functions like malloc(), free(), and memcpy(). +# All users will need to call libdeflate_set_memory_allocator(). +# # You can also specify custom CFLAGS, CPPFLAGS, and/or LDFLAGS. # ############################################################################## @@ -41,7 +45,7 @@ 1>&2 2>/dev/null; then echo $(1); fi) override CFLAGS := \ - -O2 -fomit-frame-pointer $(CFLAGS) -std=c99 -I. -Icommon \ + -O2 -fomit-frame-pointer $(CFLAGS) -std=c99 -I. \ -Wall -Wundef \ $(call cc-option,-Wpedantic) \ $(call cc-option,-Wdeclaration-after-statement) \ @@ -50,7 +54,11 @@ $(call cc-option,-Wvla) \ $(call cc-option,-Wimplicit-fallthrough) -# We don't define any CPPFLAGS, but support the user specifying it. +FREESTANDING := +ifdef FREESTANDING +override CPPFLAGS += -DFREESTANDING +LIB_CFLAGS += -ffreestanding -nostdlib +endif ############################################################################## @@ -132,7 +140,7 @@ LIB_HEADERS := $(wildcard lib/*.h) $(wildcard lib/*/*.h) -LIB_SRC := lib/aligned_malloc.c lib/deflate_decompress.c \ +LIB_SRC := lib/deflate_decompress.c lib/utils.c \ $(wildcard lib/*/cpu_features.c) DECOMPRESSION_ONLY := @@ -214,9 +222,7 @@ TEST_PROG_COMMON_SRC := programs/test_util.c TEST_PROG_SRC := programs/benchmark.c \ programs/checksum.c \ - programs/test_checksums.c \ - programs/test_incomplete_codes.c \ - programs/test_slow_decompression.c + $(filter-out $(TEST_PROG_COMMON_SRC),$(wildcard programs/test_*.c)) NONTEST_PROGRAMS := $(NONTEST_PROG_SRC:programs/%.c=%$(PROG_SUFFIX)) DEFAULT_TARGETS += $(NONTEST_PROGRAMS) diff -Nru libdeflate-1.5/Makefile.msc libdeflate-1.6/Makefile.msc --- libdeflate-1.5/Makefile.msc 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/Makefile.msc 2020-05-13 02:42:04.000000000 +0000 @@ -10,7 +10,7 @@ CC = cl LD = link AR = lib -CFLAGS = /MD /O2 -I. -Icommon +CFLAGS = /MD /O2 -I. LDFLAGS = STATIC_LIB = libdeflatestatic.lib @@ -18,13 +18,13 @@ IMPORT_LIB = libdeflate.lib STATIC_LIB_OBJ = \ - lib/aligned_malloc.obj \ lib/adler32.obj \ lib/crc32.obj \ lib/deflate_compress.obj \ lib/deflate_decompress.obj \ lib/gzip_compress.obj \ lib/gzip_decompress.obj \ + lib/utils.obj \ lib/x86/cpu_features.obj \ lib/zlib_compress.obj \ lib/zlib_decompress.obj diff -Nru libdeflate-1.5/NEWS libdeflate-1.6/NEWS --- libdeflate-1.5/NEWS 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/NEWS 2020-05-13 02:42:04.000000000 +0000 @@ -1,3 +1,24 @@ +Version 1.6: + Prevented gcc 10 from miscompiling libdeflate (workaround for + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94994). + + Removed workaround for gcc 5 and earlier producing slow code on + ARM32. If this affects you, please upgrade your compiler. + + New API function: libdeflate_zlib_decompress_ex(). It provides + the actual size of the stream that was decompressed, like the + gzip and DEFLATE equivalents. + + libdeflate_zlib_decompress() now accepts trailing bytes after + the end of the stream, like the gzip and DEFLATE equivalents. + + Added support for custom memory allocators. + (New API function: libdeflate_set_memory_allocator()) + + Added support for building the library in freestanding mode. + + Building libdeflate no longer requires CPPFLAGS=-Icommon. + Version 1.5: Fixed up stdcall support on 32-bit Windows: the functions are now exported using both suffixed and non-suffixed names, and diff -Nru libdeflate-1.5/programs/benchmark.c libdeflate-1.6/programs/benchmark.c --- libdeflate-1.5/programs/benchmark.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/benchmark.c 2020-05-13 02:42:04.000000000 +0000 @@ -503,7 +503,7 @@ int i; int ret; - program_invocation_name = get_filename(argv[0]); + begin_program(argv); while ((opt_char = tgetopt(argc, argv, optstring)) != -1) { switch (opt_char) { diff -Nru libdeflate-1.5/programs/checksum.c libdeflate-1.6/programs/checksum.c --- libdeflate-1.5/programs/checksum.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/checksum.c 2020-05-13 02:42:04.000000000 +0000 @@ -115,7 +115,7 @@ int i; int ret; - program_invocation_name = get_filename(argv[0]); + begin_program(argv); while ((opt_char = tgetopt(argc, argv, optstring)) != -1) { switch (opt_char) { diff -Nru libdeflate-1.5/programs/gzip.c libdeflate-1.6/programs/gzip.c --- libdeflate-1.5/programs/gzip.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/gzip.c 2020-05-13 02:42:04.000000000 +0000 @@ -528,7 +528,7 @@ int i; int ret; - program_invocation_name = get_filename(argv[0]); + begin_program(argv); options.to_stdout = false; options.decompress = is_gunzip(); diff -Nru libdeflate-1.5/programs/prog_util.c libdeflate-1.6/programs/prog_util.c --- libdeflate-1.5/programs/prog_util.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/prog_util.c 2020-05-13 02:42:04.000000000 +0000 @@ -112,7 +112,7 @@ * properly for directories, since a path to a directory might have trailing * slashes. */ -const tchar * +static const tchar * get_filename(const tchar *path) { const tchar *slash = tstrrchr(path, '/'); @@ -126,6 +126,17 @@ return path; } +void +begin_program(tchar *argv[]) +{ + program_invocation_name = get_filename(argv[0]); + +#ifdef FREESTANDING + /* This allows testing freestanding library builds. */ + libdeflate_set_memory_allocator(malloc, free); +#endif +} + /* Create a copy of 'path' surrounded by double quotes */ static tchar * quote_path(const tchar *path) diff -Nru libdeflate-1.5/programs/prog_util.h libdeflate-1.6/programs/prog_util.h --- libdeflate-1.5/programs/prog_util.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/prog_util.h 2020-05-13 02:42:04.000000000 +0000 @@ -39,7 +39,7 @@ #include #include -#include "common_defs.h" +#include "../common/common_defs.h" #ifdef __GNUC__ # define _printf(str_idx, args_idx) \ @@ -48,6 +48,27 @@ # define _printf(str_idx, args_idx) #endif +#ifdef _MSC_VER +/* + * Old versions (e.g. VS2010) of MSC have stdint.h but not the C99 header + * inttypes.h. Work around this by defining the PRI* macros ourselves. + */ +# define PRIu8 "hhu" +# define PRIu16 "hu" +# define PRIu32 "u" +# define PRIu64 "llu" +# define PRIi8 "hhi" +# define PRIi16 "hi" +# define PRIi32 "i" +# define PRIi64 "lli" +# define PRIx8 "hhx" +# define PRIx16 "hx" +# define PRIx32 "x" +# define PRIx64 "llx" +#else +# include +#endif + #ifdef _WIN32 /* @@ -57,7 +78,7 @@ */ #include -extern int wmain(int argc, wchar_t **argv); +int wmain(int argc, wchar_t **argv); # define tmain wmain # define tchar wchar_t # define _T(text) L##text @@ -68,7 +89,6 @@ # define topen _wopen # define tstrchr wcschr # define tstrcmp wcscmp -# define tstrcpy wcscpy # define tstrlen wcslen # define tstrrchr wcsrchr # define tstrtoul wcstoul @@ -100,7 +120,6 @@ # define topen open # define tstrchr strchr # define tstrcmp strcmp -# define tstrcpy strcpy # define tstrlen strlen # define tstrrchr strrchr # define tstrtoul strtoul @@ -116,12 +135,12 @@ extern const tchar *program_invocation_name; -extern void _printf(1, 2) msg(const char *fmt, ...); -extern void _printf(1, 2) msg_errno(const char *fmt, ...); +void _printf(1, 2) msg(const char *fmt, ...); +void _printf(1, 2) msg_errno(const char *fmt, ...); -extern void *xmalloc(size_t size); +void *xmalloc(size_t size); -extern const tchar *get_filename(const tchar *path); +void begin_program(tchar *argv[]); struct file_stream { int fd; @@ -132,27 +151,26 @@ size_t mmap_size; }; -extern int xopen_for_read(const tchar *path, bool symlink_ok, - struct file_stream *strm); -extern int xopen_for_write(const tchar *path, bool force, - struct file_stream *strm); -extern int map_file_contents(struct file_stream *strm, u64 size); +int xopen_for_read(const tchar *path, bool symlink_ok, + struct file_stream *strm); +int xopen_for_write(const tchar *path, bool force, struct file_stream *strm); +int map_file_contents(struct file_stream *strm, u64 size); -extern ssize_t xread(struct file_stream *strm, void *buf, size_t count); -extern int full_write(struct file_stream *strm, const void *buf, size_t count); +ssize_t xread(struct file_stream *strm, void *buf, size_t count); +int full_write(struct file_stream *strm, const void *buf, size_t count); -extern int xclose(struct file_stream *strm); +int xclose(struct file_stream *strm); -extern int parse_compression_level(tchar opt_char, const tchar *arg); +int parse_compression_level(tchar opt_char, const tchar *arg); -extern struct libdeflate_compressor *alloc_compressor(int level); -extern struct libdeflate_decompressor *alloc_decompressor(void); +struct libdeflate_compressor *alloc_compressor(int level); +struct libdeflate_decompressor *alloc_decompressor(void); /* tgetopt.c */ extern tchar *toptarg; extern int toptind, topterr, toptopt; -extern int tgetopt(int argc, tchar *argv[], const tchar *optstring); +int tgetopt(int argc, tchar *argv[], const tchar *optstring); #endif /* PROGRAMS_PROG_UTIL_H */ diff -Nru libdeflate-1.5/programs/test_checksums.c libdeflate-1.6/programs/test_checksums.c --- libdeflate-1.5/programs/test_checksums.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/test_checksums.c 2020-05-13 02:42:04.000000000 +0000 @@ -151,7 +151,7 @@ u8 *buffer = xmalloc(32768); u8 *guarded_buf_start, *guarded_buf_end; - program_invocation_name = get_filename(argv[0]); + begin_program(argv); alloc_guarded_buffer(32768, &guarded_buf_start, &guarded_buf_end); diff -Nru libdeflate-1.5/programs/test_custom_malloc.c libdeflate-1.6/programs/test_custom_malloc.c --- libdeflate-1.5/programs/test_custom_malloc.c 1970-01-01 00:00:00.000000000 +0000 +++ libdeflate-1.6/programs/test_custom_malloc.c 2020-05-13 02:42:04.000000000 +0000 @@ -0,0 +1,85 @@ +/* + * test_custom_malloc.c + * + * Test libdeflate_set_memory_allocator(). + * Also test injecting allocation failures. + */ + +#include "test_util.h" + +static int malloc_count = 0; +static int free_count = 0; + +static void *do_malloc(size_t size) +{ + malloc_count++; + return malloc(size); +} + +static void *do_fail_malloc(size_t size) +{ + malloc_count++; + return NULL; +} + +static void do_free(void *ptr) +{ + free_count++; + free(ptr); +} + +int +tmain(int argc, tchar *argv[]) +{ + int level; + struct libdeflate_compressor *c; + struct libdeflate_decompressor *d; + + begin_program(argv); + + /* Test that the custom allocator is actually used when requested. */ + + libdeflate_set_memory_allocator(do_malloc, do_free); + ASSERT(malloc_count == 0); + ASSERT(free_count == 0); + + for (level = 1; level <= 12; level++) { + malloc_count = free_count = 0; + c = libdeflate_alloc_compressor(level); + ASSERT(c != NULL); + ASSERT(malloc_count == 1); + ASSERT(free_count == 0); + libdeflate_free_compressor(c); + ASSERT(malloc_count == 1); + ASSERT(free_count == 1); + } + + malloc_count = free_count = 0; + d = libdeflate_alloc_decompressor(); + ASSERT(d != NULL); + ASSERT(malloc_count == 1); + ASSERT(free_count == 0); + libdeflate_free_decompressor(d); + ASSERT(malloc_count == 1); + ASSERT(free_count == 1); + + /* As long as we're here, also test injecting allocation failures. */ + + libdeflate_set_memory_allocator(do_fail_malloc, do_free); + + for (level = 1; level <= 12; level++) { + malloc_count = free_count = 0; + c = libdeflate_alloc_compressor(level); + ASSERT(c == NULL); + ASSERT(malloc_count == 1); + ASSERT(free_count == 0); + } + + malloc_count = free_count = 0; + d = libdeflate_alloc_decompressor(); + ASSERT(d == NULL); + ASSERT(malloc_count == 1); + ASSERT(free_count == 0); + + return 0; +} diff -Nru libdeflate-1.5/programs/test_incomplete_codes.c libdeflate-1.6/programs/test_incomplete_codes.c --- libdeflate-1.5/programs/test_incomplete_codes.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/test_incomplete_codes.c 2020-05-13 02:42:04.000000000 +0000 @@ -374,7 +374,7 @@ int tmain(int argc, tchar *argv[]) { - program_invocation_name = get_filename(argv[0]); + begin_program(argv); test_empty_offset_code(); test_singleton_litrunlen_code(); diff -Nru libdeflate-1.5/programs/test_slow_decompression.c libdeflate-1.6/programs/test_slow_decompression.c --- libdeflate-1.5/programs/test_slow_decompression.c 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/test_slow_decompression.c 2020-05-13 02:42:04.000000000 +0000 @@ -430,7 +430,7 @@ u8 out[10000]; u64 t, tz; - program_invocation_name = get_filename(argv[0]); + begin_program(argv); begin_performance_test(); diff -Nru libdeflate-1.5/programs/test_trailing_bytes.c libdeflate-1.6/programs/test_trailing_bytes.c --- libdeflate-1.5/programs/test_trailing_bytes.c 1970-01-01 00:00:00.000000000 +0000 +++ libdeflate-1.6/programs/test_trailing_bytes.c 2020-05-13 02:42:04.000000000 +0000 @@ -0,0 +1,154 @@ +/* + * test_trailing_bytes.c + * + * Test that decompression correctly stops at the end of the first DEFLATE, + * zlib, or gzip stream, and doesn't process any additional trailing bytes. + */ + +#include "test_util.h" + +static const struct { + size_t (LIBDEFLATEAPI *compress)( + struct libdeflate_compressor *compressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail); + enum libdeflate_result (LIBDEFLATEAPI *decompress)( + struct libdeflate_decompressor *decompressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_out_nbytes_ret); + enum libdeflate_result (LIBDEFLATEAPI *decompress_ex)( + struct libdeflate_decompressor *decompressor, + const void *in, size_t in_nbytes, + void *out, size_t out_nbytes_avail, + size_t *actual_in_nbytes_ret, + size_t *actual_out_nbytes_ret); +} codecs[] = { + { + .compress = libdeflate_deflate_compress, + .decompress = libdeflate_deflate_decompress, + .decompress_ex = libdeflate_deflate_decompress_ex, + }, { + .compress = libdeflate_zlib_compress, + .decompress = libdeflate_zlib_decompress, + .decompress_ex = libdeflate_zlib_decompress_ex, + }, { + .compress = libdeflate_gzip_compress, + .decompress = libdeflate_gzip_decompress, + .decompress_ex = libdeflate_gzip_decompress_ex, + } +}; + +int +tmain(int argc, tchar *argv[]) +{ + const size_t original_nbytes = 32768; + const size_t compressed_nbytes_total = 32768; + /* + * Don't use the full buffer for compressed data, because we want to + * test whether decompression can deal with additional trailing bytes. + * + * Note: we can't use a guarded buffer (i.e. a buffer where the byte + * after compressed_nbytes is unmapped) because the decompressor may + * read a few bytes beyond the end of the stream (but ultimately not + * actually use those bytes) as long as they are within the buffer. + */ + const size_t compressed_nbytes_avail = 30000; + size_t i; + u8 *original; + u8 *compressed; + u8 *decompressed; + struct libdeflate_compressor *c; + struct libdeflate_decompressor *d; + size_t compressed_nbytes; + enum libdeflate_result res; + size_t actual_compressed_nbytes; + size_t actual_decompressed_nbytes; + + begin_program(argv); + + ASSERT(compressed_nbytes_avail < compressed_nbytes_total); + + /* Prepare some dummy data to compress */ + original = xmalloc(original_nbytes); + ASSERT(original != NULL); + for (i = 0; i < original_nbytes; i++) + original[i] = (i % 123) + (i % 1023); + + compressed = xmalloc(compressed_nbytes_total); + ASSERT(compressed != NULL); + memset(compressed, 0, compressed_nbytes_total); + + decompressed = xmalloc(original_nbytes); + ASSERT(decompressed != NULL); + + c = libdeflate_alloc_compressor(6); + ASSERT(c != NULL); + + d = libdeflate_alloc_decompressor(); + ASSERT(d != NULL); + + for (i = 0; i < ARRAY_LEN(codecs); i++) { + compressed_nbytes = codecs[i].compress(c, original, + original_nbytes, + compressed, + compressed_nbytes_avail); + ASSERT(compressed_nbytes > 0); + ASSERT(compressed_nbytes <= compressed_nbytes_avail); + + /* Test decompress() of stream that fills the whole buffer */ + actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress(d, compressed, compressed_nbytes, + decompressed, original_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress_ex() of stream that fills the whole buffer */ + actual_compressed_nbytes = actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress_ex(d, compressed, compressed_nbytes, + decompressed, original_nbytes, + &actual_compressed_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_compressed_nbytes == compressed_nbytes); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress() of stream with trailing bytes */ + actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress(d, compressed, + compressed_nbytes_total, + decompressed, original_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + + /* Test decompress_ex() of stream with trailing bytes */ + actual_compressed_nbytes = actual_decompressed_nbytes = 0; + memset(decompressed, 0, original_nbytes); + res = codecs[i].decompress_ex(d, compressed, + compressed_nbytes_total, + decompressed, original_nbytes, + &actual_compressed_nbytes, + &actual_decompressed_nbytes); + ASSERT(res == LIBDEFLATE_SUCCESS); + ASSERT(actual_compressed_nbytes == compressed_nbytes); + ASSERT(actual_decompressed_nbytes == original_nbytes); + ASSERT(memcmp(decompressed, original, original_nbytes) == 0); + } + + printf("Trailing bytes decompression tests passed!\n"); + + free(original); + free(compressed); + free(decompressed); + libdeflate_free_compressor(c); + libdeflate_free_decompressor(d); + return 0; +} diff -Nru libdeflate-1.5/programs/test_util.h libdeflate-1.6/programs/test_util.h --- libdeflate-1.5/programs/test_util.h 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/programs/test_util.h 2020-05-13 02:42:04.000000000 +0000 @@ -38,21 +38,21 @@ # define _noreturn #endif -extern void _noreturn +void _noreturn assertion_failed(const char *expr, const char *file, int line); #define ASSERT(expr) { if (unlikely(!(expr))) \ assertion_failed(#expr, __FILE__, __LINE__); } -extern void begin_performance_test(void); +void begin_performance_test(void); -extern void alloc_guarded_buffer(size_t size, u8 **start_ret, u8 **end_ret); -extern void free_guarded_buffer(u8 *start, u8 *end); +void alloc_guarded_buffer(size_t size, u8 **start_ret, u8 **end_ret); +void free_guarded_buffer(u8 *start, u8 *end); -extern u64 timer_ticks(void); -extern u64 timer_ticks_to_ms(u64 ticks); -extern u64 timer_MB_per_s(u64 bytes, u64 ticks); -extern u64 timer_KB_per_s(u64 bytes, u64 ticks); +u64 timer_ticks(void); +u64 timer_ticks_to_ms(u64 ticks); +u64 timer_MB_per_s(u64 bytes, u64 ticks); +u64 timer_KB_per_s(u64 bytes, u64 ticks); struct output_bitstream { machine_word_t bitbuf; @@ -61,8 +61,7 @@ u8 *end; }; -extern bool put_bits(struct output_bitstream *os, machine_word_t bits, - int num_bits); -extern bool flush_bits(struct output_bitstream *os); +bool put_bits(struct output_bitstream *os, machine_word_t bits, int num_bits); +bool flush_bits(struct output_bitstream *os); #endif /* PROGRAMS_TEST_UTIL_H */ diff -Nru libdeflate-1.5/tools/run_tests.sh libdeflate-1.6/tools/run_tests.sh --- libdeflate-1.5/tools/run_tests.sh 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/tools/run_tests.sh 2020-05-13 02:42:04.000000000 +0000 @@ -173,6 +173,32 @@ fi } +# Test the library built with FREESTANDING=1. +freestanding_tests() { + test_group_included freestanding || return 0 + + WRAPPER= native_build_and_test FREESTANDING=1 + if nm libdeflate.so | grep -q ' U '; then + echo 1>&2 "Freestanding lib links to external functions!:" + nm libdeflate.so | grep ' U ' + return 1 + fi + if ldd libdeflate.so | grep -q -v '\'; then + echo 1>&2 "Freestanding lib links to external libraries!:" + ldd libdeflate.so + return 1 + fi + + if have_valgrind; then + WRAPPER="$VALGRIND" native_build_and_test FREESTANDING=1 + fi + + if have_ubsan; then + WRAPPER= native_build_and_test FREESTANDING=1 \ + CC=clang CFLAGS="$SANITIZE_CFLAGS" + fi +} + ############################################################################### checksum_benchmarks() { @@ -361,6 +387,7 @@ log " NDKDIR=$NDKDIR" native_tests +freestanding_tests checksum_benchmarks android_tests mips_tests diff -Nru libdeflate-1.5/.travis.yml libdeflate-1.6/.travis.yml --- libdeflate-1.5/.travis.yml 2019-12-28 19:33:41.000000000 +0000 +++ libdeflate-1.6/.travis.yml 2020-05-13 02:42:04.000000000 +0000 @@ -13,7 +13,7 @@ - sudo apt-get install -y libz-dev gcc-multilib libz-dev:i386 libc6-dev-i386 valgrind clang gcc-4.8-multilib gcc-mingw-w64-i686 script: - - tools/run_tests.sh native + - tools/run_tests.sh native freestanding - name: Checksum, static analysis, and edge case tests (Linux) os: linux