Commit Graph

280 Commits

Author SHA1 Message Date
Jia Tan 2959dbc735 liblzma: Update string_conversion.c to support RISC-V Filter. 2024-01-23 23:05:47 +08:00
Jia Tan 440a2eccb0 liblzma: Add RISC-V BCJ filter.
The new Filter ID is 0x0B.

Thanks to Chien Wong <m@xv97.com> for the initial version of the Filter,
the xz CLI updates, and the Autotools build system modifications.

Thanks to Igor Pavlov for his many contributions to the design of
the filter.
2024-01-23 23:05:41 +08:00
Lasse Collin cd64dd70d5 liblzma: Use 8-byte method in memcmplen.h on ARM64.
It requires fast unaligned access to 64-bit integers
and a fast instruction to count leading zeros in
a 64-bit integer (__builtin_ctzll()). This perhaps
should be enabled on some other archs too.

Thanks to Chenxi Mao for the original patch:
https://github.com/tukaani-project/xz/pull/75 (the first commit)
According to the numbers there, this may improve encoding
speed by about 3-5 %.

This enables the 8-byte method on MSVC ARM64 too which
should work but wasn't tested.
2023-12-28 17:17:39 +02:00
Lasse Collin 12c90c00f0 liblzma: Check also for __clang__ in memcmplen.h.
This change hopefully makes no practical difference as Clang
likely was detected via __GNUC__ or _MSC_VER already.
2023-12-28 17:17:39 +02:00
Jia Tan 55810780e0 liblzma: Make parameter names in function definition match declaration.
lzma_raw_encoder() and lzma_raw_encoder_init() used "options" as the
parameter name instead of "filters" (used by the declaration). "filters"
is more clear since the parameter represents the list of filters passed
to the raw encoder, each of which contains filter options.
2023-12-16 20:28:21 +08:00
Lasse Collin e7a86b94cd liblzma: Use lzma_always_inline in memcmplen.h. 2023-10-30 18:44:32 +02:00
Lasse Collin dcfe563299 liblzma: #define lzma_always_inline in common.h. 2023-10-30 18:44:32 +02:00
Lasse Collin 41113fe30a liblzma: Use lzma_attr_visibility_hidden on private extern declarations.
These variables are internal to liblzma and not exposed in the API.
2023-10-30 18:06:25 +02:00
Lasse Collin a2f5ca706a liblzma: #define lzma_attr_visibility_hidden in common.h.
In ELF shared libs:

-fvisibility=hidden affects definitions of symbols but not
declarations.[*] This doesn't affect direct calls to functions
inside liblzma as a linker can replace a call to lzma_foo@plt
with a call directly to lzma_foo when -fvisibility=hidden is used.

[*] It has to be like this because otherwise every installed
    header file would need to explictly set the symbol visibility
    to default.

When accessing extern variables that aren't defined in the
same translation unit, compiler assumes that the variable has
the default visibility and thus indirection is needed. Unlike
function calls, linker cannot optimize this.

Using __attribute__((__visibility__("hidden"))) with the extern
variable declarations tells the compiler that indirection isn't
needed because the definition is in the same shared library.

About 15+ years ago, someone told me that it would be good if
the CRC tables would be defined in the same translation unit
as the C code of the CRC functions. While I understood that it
could help a tiny amount, I didn't want to change the code because
a separate translation unit for the CRC tables was needed for the
x86 assembly code anyway. But when visibility attributes are
supported, simply marking the extern declaration with the
hidden attribute will get identical result. When there are only
a few affected variables, this is trivial to do. I wish I had
understood this back then already.
2023-10-30 18:03:39 +02:00
Lasse Collin ee7709bae5 liblzma: Move a few __attribute__ uses in function declarations.
The API headers have many attributes but these were left
as is for now.
2023-09-22 20:06:27 +03:00
Lasse Collin 18a66fbac0 Remove incorrect uses of __attribute__((__malloc__)).
xrealloc() is obviously incorrect, modern GCC docs even
mention realloc() as an example where this attribute
cannot be used.

liblzma's lzma_alloc() and lzma_alloc_zero() would be
correct uses most of the time but custom allocators
may use a memory pool or otherwise hold the pointer
so aliasing issues could happen in theory.

The xstrdup() case likely was correct but I removed it anyway.
Now there are no __malloc__ attributes left in the code.
The allocations aren't in hot paths so this should make
no practical difference.
2023-09-22 20:06:27 +03:00
Jia Tan 721e3d9f7a liblzma: Update assert in vli_ceil4().
The argument to vli_ceil4() should always guarantee the return value
is also a valid lzma_vli. Thus the highest three valid lzma_vli values
are invalid arguments. All uses of the function ensure this so the
assert is updated to match this.
2023-08-28 23:05:34 +08:00
Jia Tan ae5c07b22a liblzma: Add overflow check for Unpadded size in lzma_index_append().
This was not a security bug since there was no path to overflow
UINT64_MAX in lzma_index_append() or when it calls index_file_size().
The bug was discovered by a failing assert() in vli_ceil4() when called
from index_file_size() when unpadded_sum (the sum of the compressed size
of current Stream and the unpadded_size parameter) exceeds LZMA_VLI_MAX.

Previously, the unpadded_size parameter was checked to be not greater
than UNPADDED_SIZE_MAX, but no check was done once compressed_base was
added.

This could not have caused an integer overflow in index_file_size() when
called by lzma_index_append(). The calculation for file_size breaks down
into the sum of:

- Compressed base from all previous Streams
- 2 * LZMA_STREAM_HEADER_SIZE (size of the current Streams header and
  footer)
- stream_padding (can be set by lzma_index_stream_padding())
- Compressed base from the current Stream
- Unpadded size (parameter to lzma_index_append())

The sum of everything except for Unpadded size must be less than
LZMA_VLI_MAX. This is guarenteed by overflow checks in the functions
that can set these values including lzma_index_stream_padding(),
lzma_index_append(), and lzma_index_cat(). The maximum value for
Unpadded size is enforced by lzma_index_append() to be less than or
equal UNPADDED_SIZE_MAX. Thus, the sum cannot exceed UINT64_MAX since
LZMA_VLI_MAX is half of UINT64_MAX.

Thanks to Joona Kannisto for reporting this.
2023-08-28 23:04:56 +08:00
Dimitri Papadopoulos Orfanos 42df7c7aa1
Docs: Fix typos found by codespell 2023-07-31 20:02:21 +08:00
Jia Tan 818701ba1c liblzma: Improve comment in string_conversion.c.
The comment used "flag" when referring to decoder options. Just
referring to them as options is more clear and consistent.
2023-07-18 22:56:47 +08:00
Lasse Collin 97fd5cb669 liblzma: Tweak #if condition in memcmplen.h.
Maybe ICC always #defines _MSC_VER on Windows but now
it's very clear which code will get used.
2023-07-18 13:57:54 +03:00
Lasse Collin 40392c19f7 liblzma: Omit unnecessary parenthesis in a preprocessor directive. 2023-07-18 13:49:43 +03:00
Jia Tan 17f8844e6f liblzma: Remove non-portable empty initializer.
Commit 78704f36e7 added an empty
initializer {} to prevent a warning. The empty initializer is a GNU
extension and results in a build failure on MSVC. The -wpedantic flag
warns about empty initializers.
2023-07-08 21:24:19 +08:00
Jia Tan 78704f36e7 liblzma: Prevent uninitialzed warning in mt stream encoder.
This change only impacts the compiler warning since it was impossible
for the wait_abs struct in stream_encode_mt() to be used before it was
initialized since mythread_condtime_set() will always be called before
mythread_cond_timedwait().

Since the mythread.h code is different between the POSIX and
Windows versions, this warning was only present on Windows builds.

Thanks to Arthur S for reporting the warning and providing an initial
patch.
2023-06-29 00:06:16 +08:00
Jia Tan e3356a204c liblzma: Prevent warning for MSYS2 Windows build.
In lzma_memcmplen(), the <intrin.h> header file is only included if
_MSC_VER and _M_X64 are both defined but _BitScanForward64() was
previously used if _M_X64 was defined. GCC for MSYS2 defines _M_X64 but
not _MSC_VER so _BitScanForward64() was used without including
<intrin.h>.

Now, lzma_memcmplen() will use __builtin_ctzll() for MSYS2 GCC builds as
expected.
2023-06-28 23:59:51 +08:00
Jia Tan 8f23657498 liblzma: Exports lzma_mt_block_size() as an API function.
The lzma_mt_block_size() was previously just an internal function for
the multithreaded .xz encoder. It is used to provide a recommended Block
size for a given filter chain.

This function is helpful to determine the maximum Block size for the
multithreaded .xz encoder when one wants to change the filters between
blocks. Then, this determined Block size can be provided to
lzma_stream_encoder_mt() in the lzma_mt options parameter when
intializing the coder. This requires one to know all the filter chains
they are using before starting to encode (or at least the filter chain
that will need the largest Block size), but that isn't a bad limitation.
2023-05-11 23:54:44 +08:00
Jia Tan f41df2ac2f Windows: Include <intrin.h> when needed.
Legacy Windows did not need to #include <intrin.h> to use the MSVC
intrinsics. Newer versions likely just issue a warning, but the MSVC
documentation says to include the header file for the intrinsics we use.

GCC and Clang can "pretend" to be MSVC on Windows, so extra checks are
needed in tuklib_integer.h to only include <intrin.h> when it will is
actually needed.
2023-04-19 22:22:16 +08:00
Jia Tan 2a89670ab2 liblzma: Cleans up old commented out code. 2023-04-13 20:45:19 +08:00
Lasse Collin dfe1710784 liblzma: Silence -Wsign-conversion in SSE2 code in memcmplen.h.
Thanks to Christian Hesse for reporting the issue.
Fixes: https://github.com/tukaani-project/xz/issues/44
2023-03-19 22:45:59 +02:00
Lasse Collin 30e95bb44c liblzma: Avoid null pointer + 0 (undefined behavior in C).
In the C99 and C17 standards, section 6.5.6 paragraph 8 means that
adding 0 to a null pointer is undefined behavior. As of writing,
"clang -fsanitize=undefined" (Clang 15) diagnoses this. However,
I'm not aware of any compiler that would take advantage of this
when optimizing (Clang 15 included). It's good to avoid this anyway
since compilers might some day infer that pointer arithmetic implies
that the pointer is not NULL. That is, the following foo() would then
unconditionally return 0, even for foo(NULL, 0):

    void bar(char *a, char *b);

    int foo(char *a, size_t n)
    {
        bar(a, a + n);
        return a == NULL;
    }

In contrast to C, C++ explicitly allows null pointer + 0. So if
the above is compiled as C++ then there is no undefined behavior
in the foo(NULL, 0) call.

To me it seems that changing the C standard would be the sane
thing to do (just add one sentence) as it would ensure that a huge
amount of old code won't break in the future. Based on web searches
it seems that a large number of codebases (where null pointer + 0
occurs) are being fixed instead to be future-proof in case compilers
will some day optimize based on it (like making the above foo(NULL, 0)
return 0) which in the worst case will cause security bugs.

Some projects don't plan to change it. For example, gnulib and thus
many GNU tools currently require that null pointer + 0 is defined:

    https://lists.gnu.org/archive/html/bug-gnulib/2021-11/msg00000.html

    https://www.gnu.org/software/gnulib/manual/html_node/Other-portability-assumptions.html

In XZ Utils null pointer + 0 issue should be fixed after this
commit. This adds a few if-statements and thus branches to avoid
null pointer + 0. These check for size > 0 instead of ptr != NULL
because this way bugs where size > 0 && ptr == NULL will likely
get caught quickly. None of them are in hot spots so it shouldn't
matter for performance.

A little less readable version would be replacing

    ptr + offset

with

    offset != 0 ? ptr + offset : ptr

or creating a macro for it:

    #define my_ptr_add(ptr, offset) \
            ((offset) != 0 ? ((ptr) + (offset)) : (ptr))

Checking for offset != 0 instead of ptr != NULL allows GCC >= 8.1,
Clang >= 7, and Clang-based ICX to optimize it to the very same code
as ptr + offset. That is, it won't create a branch. So for hot code
this could be a good solution to avoid null pointer + 0. Unfortunately
other compilers like ICC 2021 or MSVC 19.33 (VS2022) will create a
branch from my_ptr_add().

Thanks to Marcin Kowalczyk for reporting the problem:
https://github.com/tukaani-project/xz/issues/36
2023-02-23 20:41:22 +02:00
Jia Tan 2c78a83c6f liblzma: Fix bug in lzma_str_from_filters() not checking filters[] length.
The bug is only a problem in applications that do not properly terminate
the filters[] array with LZMA_VLI_UNKNOWN or have more than
LZMA_FILTERS_MAX filters. This bug does not affect xz.
2023-02-03 00:42:27 +08:00
Jia Tan 8dfc029e7a liblzma: Fix typos in comments in string_conversion.c. 2023-02-03 00:42:27 +08:00
Lasse Collin 3f13bf6b9e liblzma: Silence warnings from clang -Wconditional-uninitialized.
This is similar to 2ce4f36f17.
The actual initialization of the variables is done inside
mythread_sync() macro. Clang doesn't seem to see that
the initialization code inside the macro is always executed.
2023-01-12 03:19:59 +02:00
Jia Tan 84f9687cba liblzma: Remove common.h include from common/index.h.
common/index.h is needed by liblzma internally and tests. common.h will
include and define many things that are not needed by the tests. Also,
this prevents include order problems because common.h will redefine
LZMA_API resulting in a warning.
2023-01-05 20:57:25 +08:00
Jia Tan f16e12d5e7 liblzma: Add NULL check to lzma_index_hash_append.
This is for consistency with lzma_index_append.
2023-01-02 22:20:04 +08:00
Jia Tan 203b008eb2 liblzma: Replaced hardcoded 0x0 index indicator byte with macro 2023-01-02 22:20:04 +08:00
Jia Tan 1275ebfba7 liblzma: Update documentation for lzma_filter_encoder. 2022-12-30 23:34:31 +08:00
Jia Tan 5f7ce42a16 liblzma: Fix lzma_microlzma_encoder() return value.
Using return_if_error on lzma_lzma_lclppb_encode was improper because
return_if_error is expecting an lzma_ret value, but
lzma_lzma_lclppb_encode returns a boolean. This could result in
lzma_microlzma_encoder, which would be misleading for applications.
2022-12-30 23:34:31 +08:00
Lasse Collin ac2a747e93 liblzma: Check for unexpected NULL pointers in block_header_decode().
The API docs gave an impression that such checks are done
but they actually weren't done. In practice it made little
difference since the calling code has a bug if these are NULL.

Thanks to Jia Tan for the original patch that checked for
block->filters == NULL.
2022-12-08 17:30:09 +02:00
Lasse Collin 62b270988e liblzma: Use __has_attribute(__symver__) to fix Clang detection.
If someone sets up Clang to define __GNUC__ to 10 or greater
then symvers broke. __has_attribute is supported by such GCC
and Clang versions that don't support __symver__ so this should
be much better and simpler way to detect if __symver__ is
actually supported.

Thanks to Tomasz Gajc for the bug report.
2022-12-01 20:55:21 +02:00
Lasse Collin 94adf057f2 liblzma: Silence unused variable warning when BCJ filters are disabled.
Thanks to Jia Tan for the original patch.
2022-12-01 17:54:23 +02:00
Lasse Collin cedeeca2ea liblzma: Add lzma_str_to_filters, _from_filters, and _list_filters.
lzma_str_to_filters() uses static error messages which makes
them not very precise. It tells the position in the string
where an error occurred though which helps quite a bit if
applications take advantage of it. Dynamic error messages can
be added later with a new flag if it seems important enough.
2022-11-28 21:54:24 +02:00
Lasse Collin 072ebf7b13 liblzma: Make lzma_validate_chain() available outside filter_common.c. 2022-11-28 21:02:19 +02:00
Lasse Collin cee8320646 liblzma: Use LZMA1EXT feature in lzma_microlzma_decoder().
Here too this avoids the slightly ugly method to set
the uncompressed size.

Also moved the setting of dict_size to the struct initializer.
2022-11-28 10:48:53 +02:00
Lasse Collin e310e8b6a4 liblzma: Use LZMA1EXT feature in lzma_alone_decoder().
This avoids the need to use the slightly ugly method to
set the uncompressed size.
2022-11-28 10:28:20 +02:00
Lasse Collin 33b8a24b66 liblzma: Add LZMA_FILTER_LZMA1EXT to support LZMA1 without end marker.
Some file formats need support for LZMA1 streams that don't use
the end of payload marker (EOPM) alias end of stream (EOS) marker.
So far liblzma API has supported decompressing such streams via
lzma_alone_decoder() when .lzma header specifies a known
uncompressed size. Encoding support hasn't been available in the API.

Instead of adding a new LZMA1-only API for this purpose, this commit
adds a new filter ID for use with raw encoder and decoder. The main
benefit of this approach is that then also filter chains are possible,
for example, if someone wants to implement support for .7z files that
use the x86 BCJ filter with LZMA1 (not BCJ2 as that isn't supported
in liblzma).
2022-11-27 23:16:21 +02:00
Lasse Collin 218394958c liblzma: Pass the Filter ID to LZ encoder and decoder.
This allows using two Filter IDs with the same
initialization function and data structures.
2022-11-27 18:20:33 +02:00
Lasse Collin 1663c7676b liblzma: Remove two FIXME comments. 2022-11-27 01:03:16 +02:00
Lasse Collin e782af9110 liblzma: Use lzma_filters_free() in more places. 2022-11-26 22:21:13 +02:00
Lasse Collin 93439cfafe liblzma: Add lzma_filters_update() support to the multi-threaded encoder.
A tiny downside of this is that now a 1-4 tiny allocations are made
for every Block because each worker thread needs its own copy of
the filter chain.
2022-11-24 16:25:10 +02:00
Lasse Collin 06824396b2 Build: Don't put GNU/Linux-specific symbol versions into static liblzma.
It not only makes no sense to put symbol versions into a static library
but it can also cause breakage.

By default Libtool #defines PIC if building a shared library and
doesn't define it for static libraries. This is documented in the
Libtool manual. It can be overriden using --with-pic or --without-pic.
configure.ac detects if --with-pic or --without-pic is used and then
gives an error if neither --disable-shared nor --disable-static was
used at the same time. Thus, in normal situations it works to build
both shared and static library at the same time on GNU/Linux,
only --with-pic or --without-pic requires that only one type of
library is built.

Thanks to John Paul Adrian Glaubitz from Debian for reporting
the problem that occurred on ia64:
https://www.mail-archive.com/xz-devel@tukaani.org/msg00610.html
2022-11-24 14:52:44 +02:00
Lasse Collin e1acf71072 liblzma: Refactor to use lzma_filters_free().
lzma_filters_free() sets the options to NULL and ids to
LZMA_VLI_UNKNOWN so there is no need to do it by caller;
the filter arrays will always be left in a safe state.

Also use memcpy() instead of a loop to copy a filter chain
when it is known to be safe to copy LZMA_FILTERS_MAX + 1
(even if the elements past the terminator might be uninitialized).
2022-11-24 01:32:16 +02:00
Lasse Collin cb05dbcf8b liblzma: Fix another invalid free() after memory allocation failure.
This time it can happen when lzma_stream_encoder_mt() is used
to reinitialize an existing multi-threaded Stream encoder
and one of 1-4 tiny allocations in lzma_filters_copy() fail.

It's very similar to the previous bug
10430fbf38, happening with
an array of lzma_filter structures whose old options are freed
but the replacement never arrives due to a memory allocation
failure in lzma_filters_copy().
2022-11-24 01:26:37 +02:00
Jia Tan 75f1a6c26d liblzma: Add support for LZMA_SYNC_FLUSH in the Block encoder.
The documentation mentions that lzma_block_encoder() supports
LZMA_SYNC_FLUSH but it was never added to supported_actions[]
in the internal structure. Because of this, LZMA_SYNC_FLUSH could
not be used with the Block encoder unless it was the next coder
after something like stream_encoder() or stream_encoder_mt().
2022-11-24 01:07:32 +02:00
Lasse Collin d090164517 liblzma: Add new API function lzma_filters_free().
This is small but convenient and should have been added
a long time ago.
2022-11-24 01:02:50 +02:00