Commit Graph

439 Commits

Author SHA1 Message Date
Jia Tan b02e74eb73 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-05-03 22:33:10 +03:00
Lasse Collin 3bd906f1f3 liblzma: Update project maintainers in lzma.h.
AUTHORS was updated earlier, lzma.h was simply forgotten.
2023-05-03 22:33:10 +03:00
Jia Tan 0ab5527c46 liblzma: Cleans up old commented out code. 2023-05-03 22:33:10 +03:00
Jia Tan 275e36013d Build: Removes redundant check for LZMA1 filter support. 2023-05-03 22:33:10 +03:00
Jia Tan 3e206e5c43 Bump version and soname for 5.2.11. 2023-03-18 22:25:59 +08:00
Lasse Collin 090ea9ddd3 Change a few HTTP URLs to HTTPS.
The xz man page timestamp was intentionally left unchanged.
2023-03-18 22:00:28 +08:00
Lasse Collin 09363bea46 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-03-11 21:47:47 +02:00
Jia Tan 050c6dbf96 liblzma: Fix documentation for LZMA_MEMLIMIT_ERROR.
LZMA_MEMLIMIT_ERROR was missing the "<" character needed to put
documentation after a member.
2023-03-11 21:45:26 +02:00
Lasse Collin 2ca95b7cfe 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-03-11 21:38:31 +02:00
Lasse Collin f900dd937f Fix warnings from clang -Wdocumentation. 2023-03-11 21:37:49 +02:00
Jia Tan 2155fef528 liblzma: Update documentation for lzma_filter_encoder. 2023-03-11 21:34:26 +02:00
Lasse Collin f7c2cc5561 Bump version and soname for 5.2.10. 2022-12-13 13:03:20 +02:00
Lasse Collin 7623b22d1d 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-12 15:47:17 +02:00
Lasse Collin ef315163ef 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-12 15:47:17 +02:00
Lasse Collin d8a898eb99 Bump version and soname for 5.2.9. 2022-11-30 18:33:05 +02:00
Lasse Collin 841448e36d liblzma: Remove two FIXME comments. 2022-11-29 10:46:06 +02:00
Lasse Collin b61da00c7f 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 23:50:46 +02:00
Lasse Collin 872623def5 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 10:58:04 +02:00
Jia Tan b0f8d9293c 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 10:58:04 +02:00
Lasse Collin 6997e0b5e2 liblzma: Add lzma_attr_warn_unused_result to lzma_filters_copy(). 2022-11-24 10:58:04 +02:00
Lasse Collin f94a3e3460 liblzma: Fix invalid free() after memory allocation failure.
The bug was in the single-threaded .xz Stream encoder
in the code that is used for both re-initialization and for
lzma_filters_update(). To trigger it, an application had
to either re-initialize an existing encoder instance with
lzma_stream_encoder() or use lzma_filters_update(), and
then one of the 1-4 tiny allocations in lzma_filters_copy()
(called from stream_encoder_update()) must fail. An error
was correctly reported but the encoder state was corrupted.

This is related to the recent fix in
f8ee61e74e which is good but
it wasn't enough to fix the main problem in stream_encoder.c.
2022-11-24 10:58:04 +02:00
Lasse Collin 8309385b44 liblzma: Fix language in a comment. 2022-11-24 10:57:11 +02:00
Lasse Collin 5fecba6022 liblzma: Fix infinite loop in LZMA encoder init with dict_size >= 2 GiB.
The encoder doesn't support dictionary sizes larger than 1536 MiB.
This is validated, for example, when calculating the memory usage
via lzma_raw_encoder_memusage(). It is also enforced by the LZ
part of the encoder initialization. However, LZMA encoder with
LZMA_MODE_NORMAL did an unsafe calculation with dict_size before
such validation and that results in an infinite loop if dict_size
was 2 << 30 or greater.
2022-11-24 10:57:03 +02:00
Lasse Collin 1946b2b141 liblzma: Fix two Doxygen commands in the API headers.
These were caught by clang -Wdocumentation.
2022-11-24 10:56:50 +02:00
Lasse Collin 5476089d9c Bump version and soname for 5.2.8. 2022-11-13 19:58:47 +02:00
Lasse Collin 454f567e58 liblzma: Fix building with Intel ICC (the classic compiler).
It claims __GNUC__ >= 10 but doesn't support __symver__ attribute.

Thanks to Stephen Sachs.
2022-11-11 17:16:19 +02:00
Lasse Collin 2f01169f5a liblzma: Fix incorrect #ifdef for x86 SSE2 support.
__SSE2__ is the correct macro for SSE2 support with GCC, Clang,
and ICC. __SSE2_MATH__ means doing floating point math with SSE2
instead of 387. Often the latter macro is defined if the first
one is but it was still a bug.
2022-11-11 14:36:32 +02:00
Lasse Collin 3489565b75 liblzma: Update API docs about decoder flags. 2022-11-11 13:45:39 +02:00
Lasse Collin e493771080 liblzma: Fix a comment in auto_decoder.c. 2022-11-11 13:41:43 +02:00
Lasse Collin d24a57b7fc Bump version and soname for 5.2.7. 2022-09-30 16:41:03 +03:00
Lasse Collin 369afb5199 liblzma: Add API doc note about the .xz decoder LZMA_MEMLIMIT_ERROR bug.
The bug was fixed in 660739f99a.
2022-09-30 12:20:46 +03:00
Jia Tan 166431e995 liblzma: Add dest and src NULL checks to lzma_index_cat.
The documentation states LZMA_PROG_ERROR can be returned from
lzma_index_cat. Previously, lzma_index_cat could not return
LZMA_PROG_ERROR. Now, the validation is similar to
lzma_index_append, which does a NULL check on the index
parameter.
2022-09-29 16:54:39 +03:00
Jia Tan 4ed5fd54c6 liblzma: Fix copying of check type statistics in lzma_index_cat().
The check type of the last Stream in dest was never copied to
dest->checks (the code tried to copy it but it was done too late).
This meant that the value returned by lzma_index_checks() would
only include the check type of the last Stream when multiple
lzma_indexes had been concatenated.

In xz --list this meant that the summary would only list the
check type of the last Stream, so in this sense this was only
a visual bug. However, it's possible that some applications
use this information for purposes other than merely showing
it to the users in an informational message. I'm not aware of
such applications though and it's quite possible that such
applications don't exist.

Regular streamed decompression in xz or any other application
doesn't use lzma_index_cat() and so this bug cannot affect them.
2022-09-29 16:54:39 +03:00
Lasse Collin 976f897bbb liblzma: Stream decoder: Fix restarting after LZMA_MEMLIMIT_ERROR.
If lzma_code() returns LZMA_MEMLIMIT_ERROR it is now possible
to use lzma_memlimit_set() to increase the limit and continue
decoding. This was supposed to work from the beginning but
there was a bug. With other decoders (.lzma or threaded .xz)
this already worked correctly.
2022-09-29 16:54:39 +03:00
Lasse Collin 2caa9580e5 liblzma: Stream decoder: Fix comments. 2022-09-29 16:54:39 +03:00
Lasse Collin f94da15120 liblzma: lzma_filters_copy: Keep dest[] unmodified if an error occurs.
lzma_stream_encoder() and lzma_stream_encoder_mt() always assumed
this. Before this patch, failing lzma_filters_copy() could result
in free(invalid_pointer) or invalid memory reads in stream_encoder.c
or stream_encoder_mt.c.

To trigger this, allocating memory for a filter options structure
has to fail. These are tiny allocations so in practice they very
rarely fail.

Certain badness in the filter chain array could also make
lzma_filters_copy() fail but both stream_encoder.c and
stream_encoder_mt.c validate the filter chain before
trying to copy it, so the crash cannot occur this way.
2022-09-17 00:22:11 +03:00
Jia Tan 72e1645a43 liblzma: lzma_index_append: Add missing integer overflow check.
The documentation in src/liblzma/api/lzma/index.h suggests that
both the unpadded (compressed) size and the uncompressed size
are checked for overflow, but only the unpadded size was checked.
The uncompressed check is done first since that is more likely to
occur than the unpadded or index field size overflows.
2022-09-17 00:21:54 +03:00
Lasse Collin 31d80c6b26 liblzma: Vaccinate against an ill patch from RHEL/CentOS 7.
RHEL/CentOS 7 shipped with 5.1.2alpha, including the threaded
encoder that is behind #ifdef LZMA_UNSTABLE in the API headers.
In 5.1.2alpha these symbols are under XZ_5.1.2alpha in liblzma.map.
API/ABI compatibility tracking isn't done between development
releases so newer releases didn't have XZ_5.1.2alpha anymore.

Later RHEL/CentOS 7 updated xz to 5.2.2 but they wanted to keep
the exported symbols compatible with 5.1.2alpha. After checking
the ABI changes it turned out that >= 5.2.0 ABI is backward
compatible with the threaded encoder functions from 5.1.2alpha
(but not vice versa as fixes and extensions to these functions
were made between 5.1.2alpha and 5.2.0).

In RHEL/CentOS 7, XZ Utils 5.2.2 was patched with
xz-5.2.2-compat-libs.patch to modify liblzma.map:

  - XZ_5.1.2alpha was added with lzma_stream_encoder_mt and
    lzma_stream_encoder_mt_memusage. This matched XZ Utils 5.1.2alpha.

  - XZ_5.2 was replaced with XZ_5.2.2. It is clear that this was
    an error; the intention was to keep using XZ_5.2 (XZ_5.2.2
    has never been used in XZ Utils). So XZ_5.2.2 lists all
    symbols that were listed under XZ_5.2 before the patch.
    lzma_stream_encoder_mt and _mt_memusage are included too so
    they are listed both here and under XZ_5.1.2alpha.

The patch didn't add any __asm__(".symver ...") lines to the .c
files. Thus the resulting liblzma.so exports the threaded encoder
functions under XZ_5.1.2alpha only. Listing the two functions
also under XZ_5.2.2 in liblzma.map has no effect without
matching .symver lines.

The lack of XZ_5.2 in RHEL/CentOS 7 means that binaries linked
against unpatched XZ Utils 5.2.x won't run on RHEL/CentOS 7.
This is unfortunate but this alone isn't too bad as the problem
is contained within RHEL/CentOS 7 and doesn't affect users
of other distributions. It could also be fixed internally in
RHEL/CentOS 7.

The second problem is more serious: In XZ Utils 5.2.2 the API
headers don't have #ifdef LZMA_UNSTABLE for obvious reasons.
This is true in RHEL/CentOS 7 version too. Thus now programs
using new APIs can be compiled without an extra #define. However,
the programs end up depending on symbol version XZ_5.1.2alpha
(and possibly also XZ_5.2.2) instead of XZ_5.2 as they would
with an unpatched XZ Utils 5.2.2. This means that such binaries
won't run on other distributions shipping XZ Utils >= 5.2.0 as
they don't provide XZ_5.1.2alpha or XZ_5.2.2; they only provide
XZ_5.2 (and XZ_5.0). (This includes RHEL/CentOS 8 as the patch
luckily isn't included there anymore with XZ Utils 5.2.4.)

Binaries built by RHEL/CentOS 7 users get distributed and then
people wonder why they don't run on some other distribution.
Seems that people have found out about the patch and been copying
it to some build scripts, seemingly curing the symptoms but
actually spreading the illness further and outside RHEL/CentOS 7.

The ill patch seems to be from late 2016 (RHEL 7.3) and in 2017 it
had spread at least to EasyBuild. I heard about the events only
recently. :-(

This commit splits liblzma.map into two versions: one for
GNU/Linux and another for other OSes that can use symbol versioning
(FreeBSD, Solaris, maybe others). The Linux-specific file and the
matching additions to .c files add full compatibility with binaries
that have been built against a RHEL/CentOS-patched liblzma. Builds
for OSes other than GNU/Linux won't get the vaccine as they should
be immune to the problem (I really hope that no build script uses
the RHEL/CentOS 7 patch outside GNU/Linux).

The RHEL/CentOS compatibility symbols XZ_5.1.2alpha and XZ_5.2.2
are intentionally put *after* XZ_5.2 in liblzma_linux.map. This way
if one forgets to #define HAVE_SYMBOL_VERSIONS_LINUX when building,
the resulting liblzma.so.5 will have lzma_stream_encoder_mt@@XZ_5.2
since XZ_5.2 {...} is the first one that lists that function.
Without HAVE_SYMBOL_VERSIONS_LINUX @XZ_5.1.2alpha and @XZ_5.2.2
will be missing but that's still a minor problem compared to
only having lzma_stream_encoder_mt@@XZ_5.1.2alpha!

The "local: *;" line was moved to XZ_5.0 so that it doesn't need
to be moved around. It doesn't matter where it is put.

Having two similar liblzma_*.map files is a bit silly as it is,
at least for now, easily possible to generate the generic one
from the Linux-specific file. But that adds extra steps and
increases the risk of mistakes when supporting more than one
build system. So I rather maintain two files in parallel and let
validate_map.sh check that they are in sync when "make mydist"
is run.

This adds .symver lines for lzma_stream_encoder_mt@XZ_5.2.2 and
lzma_stream_encoder_mt_memusage@XZ_5.2.2 even though these
weren't exported by RHEL/CentOS 7 (only @@XZ_5.1.2alpha was
for these two). I added these anyway because someone might
misunderstand the RHEL/CentOS 7 patch and think that @XZ_5.2.2
(@@XZ_5.2.2) versions were exported too.

At glance one could suggest using __typeof__ to copy the function
prototypes when making aliases. However, this doesn't work trivially
because __typeof__ won't copy attributes (lzma_nothrow, lzma_pure)
and it won't change symbol visibility from hidden to default (done
by LZMA_API()). Attributes could be copied with __copy__ attribute
but that needs GCC 9 and a fallback method would be needed anyway.

This uses __symver__ attribute with GCC >= 10 and
__asm__(".symver ...") with everything else. The attribute method
is required for LTO (-flto) support with GCC. Using -flto with
GCC older than 10 is now broken on GNU/Linux and will not be fixed
(can silently result in a broken liblzma build that has dangerously
incorrect symbol versions). LTO builds with Clang seem to work
with the traditional __asm__(".symver ...") method.

Thanks to Boud Roukema for reporting the problem and discussing
the details and testing the fix.
2022-09-16 19:30:05 +03:00
Lasse Collin 8dfed05bda Bump version and soname for 5.2.6. 2022-08-12 14:30:13 +03:00
Jia Tan 76a5a752b8 liblzma: Refactor lzma_mf_is_supported() to use a switch-statement. 2022-07-25 18:36:49 +03:00
Lasse Collin e96bdf7189 liblzma: Rename a variable and improve a comment. 2022-07-24 11:37:44 +03:00
Lasse Collin ff54b557fe liblzma: Add optional autodetection of LZMA end marker.
Turns out that this is needed for .lzma files as the spec in
LZMA SDK says that end marker may be present even if the size
is stored in the header. Such files are rare but exist in the
real world. The code in liblzma is so old that the spec didn't
exist in LZMA SDK back then and I had understood that such
files weren't possible (the lzma tool in LZMA SDK didn't
create such files).

This modifies the internal API so that LZMA decoder can be told
if EOPM is allowed even when the uncompressed size is known.
It's allowed with .lzma and not with other uses.

Thanks to Karl Beldan for reporting the problem.
2022-07-24 11:36:56 +03:00
Lasse Collin f12ce0f23a liblzma: Fix docs: lzma_block_decoder() cannot return LZMA_UNSUPPORTED_CHECK.
If Check is unsupported, it will be silently ignored.
It's the caller's job to handle it.
2022-07-12 19:30:40 +03:00
Lasse Collin 4125667311 liblzma: Index hash: Change return value type of hash_append() to void. 2022-07-12 19:30:40 +03:00
Lasse Collin 7c3ce02df0 liblzma: Minor addition to lzma_vli_size() API doc.
Thanks to Jia Tan.
2022-07-12 19:30:40 +03:00
Lasse Collin b8f667fe0c liblzma: Check the return value of lzma_index_append() in threaded encoder.
If lzma_index_append() failed (most likely memory allocation failure)
it could have gone unnoticed and the resulting .xz file would have
an incorrect Index. Decompressing such a file would produce the
correct uncompressed data but then an error would occur when
verifying the Index field.
2022-07-12 19:30:40 +03:00
Ed Maste 748ef08338 liblzma: Use non-executable stack on FreeBSD as on Linux 2022-07-12 19:30:40 +03:00
Lasse Collin 068a6e3286 liblzma: Make Block decoder catch certain types of errors better.
Now it limits the input and output buffer sizes that are
passed to a raw decoder. This way there's no need to check
if the sizes can grow too big or overflow when updating
Compressed Size and Uncompressed Size counts. This also means
that a corrupt file cannot cause the raw decoder to process
useless extra input or output that would exceed the size info
in Block Header (and thus cause LZMA_DATA_ERROR anyway).

More importantly, now the size information is verified more
carefully in case raw decoder returns LZMA_OK. This doesn't
really matter with the current single-threaded .xz decoder
as the errors would be detected slightly later anyway. But
this helps avoiding corner cases in the upcoming threaded
decompressor, and it might help other Block decoder uses
outside liblzma too.

The test files bad-1-lzma2-{9,10,11}.xz test these conditions.
With the single-threaded .xz decoder the only difference is
that LZMA_DATA_ERROR is detected in a difference place now.
2022-07-12 19:30:40 +03:00
jiat75 e20ce2b122 liblzma: Add NULL checks to LZMA and LZMA2 properties encoders.
Previously lzma_lzma_props_encode() and lzma_lzma2_props_encode()
assumed that the options pointers must be non-NULL because the
with these filters the API says it must never be NULL. It is
good to do these checks anyway.
2022-07-12 19:03:51 +03:00
Lasse Collin d8b294af03 liblzma: Use _MSVC_LANG to detect when "noexcept" can be used with MSVC.
By default, MSVC always sets __cplusplus to 199711L. The real
C++ standard version is available in _MSVC_LANG (or one could
use /Zc:__cplusplus to set __cplusplus correctly).

Fixes <https://sourceforge.net/p/lzmautils/discussion/708858/thread/f6bc3b108a/>.

Thanks to Dan Weiss.
2022-07-12 19:01:09 +03:00