https://github.com/qxy11 updated https://github.com/llvm/llvm-project/pull/220092
>From 2a96a7e6bb691e5579f10d033a08ce67856f43c3 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 26 Aug 2026 10:17:50 -0700 Subject: [PATCH 1/6] [Support] Add xz (lzma) decompression Adds compression::xz::decompress(), guarded by a new LLVM_ENABLE_LZMA CMake option that looks for liblzma via the stock FindLibLZMA module. The implementation is ported from lldb_private::lzma, which is currently the only xz decompressor in the tree; a follow-up switches LLDB over to this one so the logic is not duplicated. Unlike zlib and zstd, xz records the uncompressed size in its stream index, so decompress() recovers it and sizes the output buffer itself rather than making the caller supply it. For the same reason xz is not added to compression::Format: that enum models the schemes usable for SHF_COMPRESSED sections, which carry the size out-of-band and have a corresponding ELFCOMPRESS_* constant. xz has neither. Only decompression is implemented, since the motivating use case is reading the .gnu_debugdata (MiniDebugInfo) section. Tests are gated on the new "lzma" lit feature. --- llvm/CMakeLists.txt | 2 + llvm/cmake/config-ix.cmake | 11 ++ llvm/cmake/modules/LLVMConfig.cmake.in | 5 + llvm/docs/CMake.md | 6 + llvm/include/llvm/Config/llvm-config.h.cmake | 3 + llvm/include/llvm/Support/Compression.h | 15 +++ llvm/lib/Support/CMakeLists.txt | 17 +++ llvm/lib/Support/Compression.cpp | 125 ++++++++++++++++++ llvm/test/CMakeLists.txt | 1 + llvm/test/lit.site.cfg.py.in | 1 + llvm/unittests/Support/CompressionTest.cpp | 61 +++++++++ .../llvm/include/llvm/Config/BUILD.gn | 3 + llvm/utils/lit/lit/llvm/config.py | 3 + .../llvm-project-overlay/llvm/BUILD.bazel | 4 + .../third-party/BUILD.bazel | 33 +++++ utils/bazel/llvm_configs/llvm-config.h.cmake | 3 + 16 files changed, 293 insertions(+) diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 44299d51d784a1..5893c8d6411a33 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -676,6 +676,8 @@ set(LLVM_ENABLE_ZSTD "ON" CACHE STRING "Use zstd for compression/decompression i set(LLVM_USE_STATIC_ZSTD FALSE CACHE BOOL "Use static version of zstd. Can be TRUE, FALSE") +set(LLVM_ENABLE_LZMA "ON" CACHE STRING "Use liblzma for xz decompression if available. Can be ON, OFF, or FORCE_ON") + set(LLVM_ENABLE_CURL "OFF" CACHE STRING "Use libcurl for the HTTP client if available. Can be ON, OFF, or FORCE_ON") set(LLVM_HAS_LOGF128 "OFF" CACHE STRING "Use logf128 to constant fold fp128 logarithm calls. Can be ON, OFF, or FORCE_ON") diff --git a/llvm/cmake/config-ix.cmake b/llvm/cmake/config-ix.cmake index ab02554af0b53f..8d1d0d0f5adcb1 100644 --- a/llvm/cmake/config-ix.cmake +++ b/llvm/cmake/config-ix.cmake @@ -217,6 +217,17 @@ if(LLVM_ENABLE_ZSTD) endif() endif() +if(LLVM_ENABLE_LZMA) + if(LLVM_ENABLE_LZMA STREQUAL FORCE_ON) + find_package(LibLZMA REQUIRED) + elseif(NOT LLVM_USE_SANITIZER MATCHES "Memory.*") + find_package(LibLZMA) + endif() + set(LLVM_ENABLE_LZMA "${LIBLZMA_FOUND}") +else() + set(LLVM_ENABLE_LZMA 0) +endif() + if(LLVM_ENABLE_LIBXML2) if(LLVM_ENABLE_LIBXML2 STREQUAL FORCE_ON) find_package(LibXml2 REQUIRED) diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in index 6f5fcc6a926f93..a0d4c09ed836ab 100644 --- a/llvm/cmake/modules/LLVMConfig.cmake.in +++ b/llvm/cmake/modules/LLVMConfig.cmake.in @@ -82,6 +82,11 @@ if(LLVM_ENABLE_ZSTD) find_package(zstd) endif() +set(LLVM_ENABLE_LZMA @LLVM_ENABLE_LZMA@) +if(LLVM_ENABLE_LZMA) + find_package(LibLZMA) +endif() + set(LLVM_ENABLE_LIBXML2 @LLVM_ENABLE_LIBXML2@) if(LLVM_ENABLE_LIBXML2) find_package(LibXml2) diff --git a/llvm/docs/CMake.md b/llvm/docs/CMake.md index 41c9b0f1ae9474..0b55c26084f9fc 100644 --- a/llvm/docs/CMake.md +++ b/llvm/docs/CMake.md @@ -607,6 +607,12 @@ sub-projects. Nearly all of these variable names begin with `LLVM_`. enabling link-time optimization. Possible values are `Off`, `On`, `Thin` and `Full`. Defaults to OFF. +**LLVM_ENABLE_LZMA**:STRING + +: Used to decide if LLVM tools should support decompression of xz streams + with liblzma. Allowed values are `OFF`, `ON` (default, enable if liblzma is + found), and `FORCE_ON` (error if liblzma is not found). + **LLVM_ENABLE_MODULES**:BOOL : Compile with [Clang Header diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake b/llvm/include/llvm/Config/llvm-config.h.cmake index 9ac0115ee2184f..b30550ec8ce00a 100644 --- a/llvm/include/llvm/Config/llvm-config.h.cmake +++ b/llvm/include/llvm/Config/llvm-config.h.cmake @@ -98,6 +98,9 @@ /* Define if zstd compression is available */ #cmakedefine01 LLVM_ENABLE_ZSTD +/* Define if xz (lzma) decompression is available */ +#cmakedefine01 LLVM_ENABLE_LZMA + /* Define if LLVM is using tflite */ #cmakedefine LLVM_HAVE_TFLITE diff --git a/llvm/include/llvm/Support/Compression.h b/llvm/include/llvm/Support/Compression.h index 246ccbd6f6dcfe..06188af2526e60 100644 --- a/llvm/include/llvm/Support/Compression.h +++ b/llvm/include/llvm/Support/Compression.h @@ -76,6 +76,21 @@ LLVM_ABI Error decompress(ArrayRef<uint8_t> Input, } // End of namespace zstd +namespace xz { + +/// Return true if LLVM was built with LZMA support (LLVM_ENABLE_LZMA). +LLVM_ABI bool isAvailable(); + +/// Decompress an xz stream. Unlike zlib and zstd, the uncompressed size does +/// not need to be supplied by the caller: it is recovered from the stream +/// index, and \p Output is resized to fit. +/// +/// Requires isAvailable(); calling this otherwise is a fatal error. +LLVM_ABI Error decompress(ArrayRef<uint8_t> Input, + SmallVectorImpl<uint8_t> &Output); + +} // End of namespace xz + enum class Format { Zlib, Zstd, diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 1a3fa39c81e29f..db6bd2abb1130d 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -37,6 +37,10 @@ if(LLVM_ENABLE_ZSTD) list(APPEND imported_libs ${zstd_target}) endif() +if(LLVM_ENABLE_LZMA) + list(APPEND imported_libs LibLZMA::LibLZMA) +endif() + if( WIN32 ) # libuuid required for FOLDERID_Profile usage in lib/Support/Windows/Path.inc. # advapi32 required for CryptAcquireContextW in lib/Support/Windows/Path.inc. @@ -380,6 +384,19 @@ if(LLVM_ENABLE_ZSTD) endif() endif() +if(LLVM_ENABLE_LZMA) + # CMAKE_BUILD_TYPE is only meaningful to single-configuration generators. + if(CMAKE_BUILD_TYPE) + string(TOUPPER ${CMAKE_BUILD_TYPE} build_type) + get_property(lzma_library TARGET LibLZMA::LibLZMA PROPERTY LOCATION_${build_type}) + endif() + if(NOT lzma_library) + get_property(lzma_library TARGET LibLZMA::LibLZMA PROPERTY LOCATION) + endif() + get_library_name(${lzma_library} lzma_library) + set(llvm_system_libs ${llvm_system_libs} "${lzma_library}") +endif() + set_property(TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS "${llvm_system_libs}") diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp index 3979ca6acaf74e..6e6539cf91db56 100644 --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -23,6 +23,9 @@ #if LLVM_ENABLE_ZSTD #include <zstd.h> #endif +#if LLVM_ENABLE_LZMA +#include <lzma.h> +#endif using namespace llvm; using namespace llvm::compression; @@ -242,3 +245,125 @@ Error zstd::decompress(ArrayRef<uint8_t> Input, llvm_unreachable("zstd::decompress is unavailable"); } #endif + +#if LLVM_ENABLE_LZMA + +bool xz::isAvailable() { return true; } + +// Returns a C string rather than a StringRef because every caller feeds the +// result to a printf-style "%s", which requires NUL termination. +static const char *convertLZMACodeToString(lzma_ret Code) { + switch (Code) { + case LZMA_STREAM_END: + return "lzma error: LZMA_STREAM_END"; + case LZMA_NO_CHECK: + return "lzma error: LZMA_NO_CHECK"; + case LZMA_UNSUPPORTED_CHECK: + return "lzma error: LZMA_UNSUPPORTED_CHECK"; + case LZMA_GET_CHECK: + return "lzma error: LZMA_GET_CHECK"; + case LZMA_MEM_ERROR: + return "lzma error: LZMA_MEM_ERROR"; + case LZMA_MEMLIMIT_ERROR: + return "lzma error: LZMA_MEMLIMIT_ERROR"; + case LZMA_FORMAT_ERROR: + return "lzma error: LZMA_FORMAT_ERROR"; + case LZMA_OPTIONS_ERROR: + return "lzma error: LZMA_OPTIONS_ERROR"; + case LZMA_DATA_ERROR: + return "lzma error: LZMA_DATA_ERROR"; + case LZMA_BUF_ERROR: + return "lzma error: LZMA_BUF_ERROR"; + case LZMA_PROG_ERROR: + return "lzma error: LZMA_PROG_ERROR"; + default: + llvm_unreachable("unknown or unexpected lzma status code"); + } +} + +static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> InputBuffer) { + lzma_stream_flags opts{}; + if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { + return createStringError( + inconvertibleErrorCode(), + "size of xz-compressed blob (%zu bytes) is smaller than the " + "LZMA_STREAM_HEADER_SIZE (%zu bytes)", + InputBuffer.size(), size_t(LZMA_STREAM_HEADER_SIZE)); + } + + // Decode xz footer. + lzma_ret xzerr = lzma_stream_footer_decode( + &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); + if (xzerr != LZMA_OK) { + return createStringError(inconvertibleErrorCode(), + "lzma_stream_footer_decode()=%s", + convertLZMACodeToString(xzerr)); + } + if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { + return createStringError( + inconvertibleErrorCode(), + "xz-compressed buffer size (%zu bytes) too small (required at " + "least %" PRIu64 " bytes) ", + InputBuffer.size(), + uint64_t(opts.backward_size + LZMA_STREAM_HEADER_SIZE)); + } + + // Decode xz index. + lzma_index *xzindex; + uint64_t memlimit(UINT64_MAX); + size_t inpos = 0; + xzerr = lzma_index_buffer_decode( + &xzindex, &memlimit, nullptr, + InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) + .data(), + &inpos, InputBuffer.size()); + if (xzerr != LZMA_OK) { + return createStringError(inconvertibleErrorCode(), + "lzma_index_buffer_decode()=%s", + convertLZMACodeToString(xzerr)); + } + + // Get size of uncompressed file to construct an in-memory buffer of the + // same size on the calling end (if needed). + uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); + + // Deallocate xz index as it is no longer needed. + lzma_index_end(xzindex, nullptr); + + return uncompressedSize; +} + +Error xz::decompress(ArrayRef<uint8_t> Input, + SmallVectorImpl<uint8_t> &Output) { + Expected<uint64_t> uncompressedSize = getUncompressedSize(Input); + + if (auto err = uncompressedSize.takeError()) + return err; + + Output.resize(*uncompressedSize); + + // Decompress xz buffer to buffer. + uint64_t memlimit = UINT64_MAX; + size_t inpos = 0; + size_t outpos = 0; + lzma_ret ret = lzma_stream_buffer_decode(&memlimit, 0, nullptr, Input.data(), + &inpos, Input.size(), Output.data(), + &outpos, Output.size()); + if (ret != LZMA_OK) { + return createStringError(inconvertibleErrorCode(), + "lzma_stream_buffer_decode()=%s", + convertLZMACodeToString(ret)); + } + + return Error::success(); +} + +#else + +bool xz::isAvailable() { return false; } +Error xz::decompress(ArrayRef<uint8_t> Input, + SmallVectorImpl<uint8_t> &Output) { + llvm_unreachable("xz::decompress is unavailable"); +} + +#endif diff --git a/llvm/test/CMakeLists.txt b/llvm/test/CMakeLists.txt index a2269597fe5e69..0a2e8749acc062 100644 --- a/llvm/test/CMakeLists.txt +++ b/llvm/test/CMakeLists.txt @@ -9,6 +9,7 @@ llvm_canonicalize_cmake_booleans( LLVM_ENABLE_HTTPLIB LLVM_ENABLE_ZLIB LLVM_ENABLE_ZSTD + LLVM_ENABLE_LZMA LLVM_ENABLE_LIBXML2 LLVM_LINK_LLVM_DYLIB LLVM_TOOL_LTO_BUILD diff --git a/llvm/test/lit.site.cfg.py.in b/llvm/test/lit.site.cfg.py.in index b13ccd74d09287..c54a687c06e742 100644 --- a/llvm/test/lit.site.cfg.py.in +++ b/llvm/test/lit.site.cfg.py.in @@ -39,6 +39,7 @@ config.llvm_use_intel_jitevents = @LLVM_USE_INTEL_JITEVENTS@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" config.have_zlib = @LLVM_ENABLE_ZLIB@ config.have_zstd = @LLVM_ENABLE_ZSTD@ +config.have_lzma = @LLVM_ENABLE_LZMA@ config.have_libxml2 = @LLVM_ENABLE_LIBXML2@ config.have_curl = @LLVM_ENABLE_CURL@ config.have_httplib = @LLVM_ENABLE_HTTPLIB@ diff --git a/llvm/unittests/Support/CompressionTest.cpp b/llvm/unittests/Support/CompressionTest.cpp index 5d326cafbe3a1c..508ceb5ab671ab 100644 --- a/llvm/unittests/Support/CompressionTest.cpp +++ b/llvm/unittests/Support/CompressionTest.cpp @@ -111,4 +111,65 @@ TEST(CompressionTest, Zstd) { testZstdCompression(BinaryDataStr, zstd::DefaultCompression); } #endif + +#if LLVM_ENABLE_LZMA + +// LLVM implements xz decompression but not compression, so these are +// checked-in literals rather than round trips. + +/// `xz --check=crc32 -9` of the empty string. +static constexpr uint8_t XzEmptyData[] = { + 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x01, 0x69, 0x22, 0xde, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0x44, 0x21, 0x90, 0x42, + 0x99, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a, +}; + +/// `xz --check=crc32 -9` of "hello, world!". +static constexpr uint8_t XzTextData[] = { + 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x01, 0x69, 0x22, 0xde, 0x36, + 0x02, 0x00, 0x21, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x10, 0xcf, 0x58, 0xcc, + 0x01, 0x00, 0x0c, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, + 0x72, 0x6c, 0x64, 0x21, 0x00, 0x00, 0x00, 0x00, 0x13, 0x8d, 0x98, 0x58, + 0x00, 0x01, 0x21, 0x0d, 0x75, 0xdc, 0xa8, 0xd2, 0x90, 0x42, 0x99, 0x0d, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a, +}; + +static void testXzDecompression(ArrayRef<uint8_t> Compressed, + StringRef Expected) { + SmallVector<uint8_t, 0> Uncompressed; + + // Check that uncompressed buffer is the same as original. The uncompressed + // size is recovered from the stream index, not supplied by the caller. + Error E = xz::decompress(Compressed, Uncompressed); + EXPECT_FALSE(std::move(E)); + EXPECT_EQ(Expected, toStringRef(Uncompressed)); + + // Decompression fails if the buffer is too small to hold a stream header. + E = xz::decompress(Compressed.take_front(4), Uncompressed); + EXPECT_EQ("size of xz-compressed blob (4 bytes) is smaller than the " + "LZMA_STREAM_HEADER_SIZE (12 bytes)", + llvm::toString(std::move(E))); + + // Decompression fails if the footer holding the uncompressed size is gone. + E = xz::decompress(Compressed.drop_back(4), Uncompressed); + EXPECT_EQ("lzma_stream_footer_decode()=lzma error: LZMA_FORMAT_ERROR", + llvm::toString(std::move(E))); + + if (!Expected.empty()) { + // Decompression fails if the compressed payload is corrupt. + SmallVector<uint8_t, 0> Corrupt(Compressed.begin(), Compressed.end()); + Corrupt[24] ^= 0xff; + E = xz::decompress(Corrupt, Uncompressed); + EXPECT_EQ("lzma_stream_buffer_decode()=lzma error: LZMA_DATA_ERROR", + llvm::toString(std::move(E))); + } } + +TEST(CompressionTest, Xz) { + EXPECT_TRUE(xz::isAvailable()); + + testXzDecompression(XzEmptyData, ""); + testXzDecompression(XzTextData, "hello, world!"); +} +#endif +} // namespace diff --git a/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn b/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn index 5678886ea7183f..b1adfe6c1d9d46 100644 --- a/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/include/llvm/Config/BUILD.gn @@ -393,6 +393,9 @@ write_cmake_config("llvm-config") { values += [ "LLVM_ENABLE_ZSTD=" ] } + # FIXME: no liblzma support in the GN build yet; xz decompression is off. + values += [ "LLVM_ENABLE_LZMA=" ] + if (llvm_enable_libcurl) { values += [ "LLVM_ENABLE_CURL=1" ] } else { diff --git a/llvm/utils/lit/lit/llvm/config.py b/llvm/utils/lit/lit/llvm/config.py index 953782d5765df0..138324d6ec83a1 100644 --- a/llvm/utils/lit/lit/llvm/config.py +++ b/llvm/utils/lit/lit/llvm/config.py @@ -150,6 +150,9 @@ def __init__(self, lit_config, config): have_zstd = getattr(config, "have_zstd", None) if have_zstd: features.add("zstd") + have_lzma = getattr(config, "have_lzma", None) + if have_lzma: + features.add("lzma") if getattr(config, "reverse_iteration", None): features.add("reverse_iteration") diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel index 9f2ae504adb171..f2bb596186791b 100644 --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -524,6 +524,10 @@ cc_library( # be an empty library unless zstd is enabled, in which case it will # both provide the necessary dependencies and configuration defines. "//third-party:zstd", + # We unconditionally depend on the custom LLVM lzma wrapper. This only + # provides the configuration define unless lzma is enabled, in which + # case it also links the system liblzma. + "//third-party:lzma", "//libc:shared_math_headers_for_apfloat", ], ) diff --git a/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel b/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel index e2131005a693ca..2ceddfef3784a8 100644 --- a/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel @@ -2,6 +2,7 @@ # See https://llvm.org/LICENSE.txt for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load("@rules_cc//cc:cc_library.bzl", "cc_library") load(":cc_library_wrapper.bzl", "cc_library_wrapper") package(default_visibility = ["//visibility:public"]) @@ -62,3 +63,35 @@ cc_library_wrapper( "//conditions:default": [], }), ) + +bool_flag( + name = "llvm_enable_lzma", + build_setting_default = False, +) + +config_setting( + name = "llvm_lzma_enabled", + flag_values = {":llvm_enable_lzma": "true"}, +) + +# Unlike zlib and zstd there is no liblzma module in the Bazel registry, so this +# links the system library rather than building one from source. That is why it +# is a plain cc_library with linkopts instead of a cc_library_wrapper, and why +# it defaults to off. +cc_library( + name = "lzma", + defines = select({ + ":llvm_lzma_enabled": [ + "LLVM_ENABLE_LZMA=1", + ], + "//conditions:default": [ + "LLVM_ENABLE_LZMA=0", + ], + }), + linkopts = select({ + ":llvm_lzma_enabled": [ + "-llzma", + ], + "//conditions:default": [], + }), +) diff --git a/utils/bazel/llvm_configs/llvm-config.h.cmake b/utils/bazel/llvm_configs/llvm-config.h.cmake index 9ac0115ee2184f..b30550ec8ce00a 100644 --- a/utils/bazel/llvm_configs/llvm-config.h.cmake +++ b/utils/bazel/llvm_configs/llvm-config.h.cmake @@ -98,6 +98,9 @@ /* Define if zstd compression is available */ #cmakedefine01 LLVM_ENABLE_ZSTD +/* Define if xz (lzma) decompression is available */ +#cmakedefine01 LLVM_ENABLE_LZMA + /* Define if LLVM is using tflite */ #cmakedefine LLVM_HAVE_TFLITE >From c24029d6d1e5193ac5ac73921706e40a2662e708 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 26 Aug 2026 13:49:40 -0700 Subject: [PATCH 2/6] [Support] Fix over-declared input size when decoding the xz index lzma_index_buffer_decode() was given a pointer to the start of the stream index but the size of the *whole* stream, so it was told it could read far past the end of the buffer. On a 63252-byte stream with a 12-byte index the declared extent ran 63228 bytes beyond the allocation. Valid streams are unaffected: the index is self-delimiting and CRC-checked, so liblzma stops at its end. A malformed index could make it scan further, which matters because .gnu_debugdata comes from arbitrary third-party binaries. Pass exactly the index: drop the 12-byte footer, then take the backward_size bytes the footer declares. This bug is inherited from lldb_private::lzma, where it still exists; it is split out here so it can be reviewed and back-ported on its own. --- llvm/lib/Support/Compression.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp index 6e6539cf91db56..9337fc2cf23688 100644 --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -312,11 +312,11 @@ static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> InputBuffer) { lzma_index *xzindex; uint64_t memlimit(UINT64_MAX); size_t inpos = 0; - xzerr = lzma_index_buffer_decode( - &xzindex, &memlimit, nullptr, - InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) - .data(), - &inpos, InputBuffer.size()); + ArrayRef<uint8_t> IndexBuffer = InputBuffer.drop_back(LZMA_STREAM_HEADER_SIZE) + .take_back(opts.backward_size); + xzerr = + lzma_index_buffer_decode(&xzindex, &memlimit, nullptr, IndexBuffer.data(), + &inpos, IndexBuffer.size()); if (xzerr != LZMA_OK) { return createStringError(inconvertibleErrorCode(), "lzma_index_buffer_decode()=%s", >From 72c2d1c4930aa1818f6a68cb4cac3757dbbb24c6 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 26 Aug 2026 10:17:51 -0700 Subject: [PATCH 3/6] [lldb] Use llvm::compression::xz instead of lldb_private::lzma Now that LLVM's Support library can decompress xz streams, LLDB does not need its own copy. Deletes lldb/Host/LZMA.{h,cpp} and points ObjectFileELF's .gnu_debugdata handling at compression::xz. The LLDB_ENABLE_LZMA CMake option is dropped in favor of LLVM_ENABLE_LZMA, so there is a single knob for the whole build. LLDB no longer links liblzma directly; it picks it up through LLVMSupport. The only behavioral change is the wording of the decompression failure message, which the corrupt-xz test is updated for. --- .ci/green-dragon/lldb-ubuntu.groovy | 2 +- lldb/cmake/modules/LLDBConfig.cmake | 5 - lldb/docs/resources/build.md | 1 - lldb/include/lldb/Host/Config.h.cmake | 2 - lldb/include/lldb/Host/LZMA.h | 35 ----- lldb/source/Core/Debugger.cpp | 2 +- lldb/source/Host/CMakeLists.txt | 4 - lldb/source/Host/common/LZMA.cpp | 146 ------------------ .../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 7 +- lldb/test/CMakeLists.txt | 2 +- lldb/test/Shell/lit.cfg.py | 3 - lldb/test/Shell/lit.site.cfg.py.in | 2 +- .../secondary/lldb/include/lldb/Host/BUILD.gn | 1 - .../gn/secondary/lldb/source/Host/BUILD.gn | 4 - llvm/utils/gn/secondary/lldb/test/BUILD.gn | 2 +- .../llvm-project-overlay/lldb/BUILD.bazel | 28 +--- 16 files changed, 10 insertions(+), 236 deletions(-) delete mode 100644 lldb/include/lldb/Host/LZMA.h delete mode 100644 lldb/source/Host/common/LZMA.cpp diff --git a/.ci/green-dragon/lldb-ubuntu.groovy b/.ci/green-dragon/lldb-ubuntu.groovy index 2505b9766c014b..8850b706b565f5 100644 --- a/.ci/green-dragon/lldb-ubuntu.groovy +++ b/.ci/green-dragon/lldb-ubuntu.groovy @@ -74,7 +74,7 @@ pip3 install --break-system-packages -r /workspace/llvm-zorg/zorg/jenkins/jobs/r -DLLDB_ENABLE_CURSES=ON \ -DLLDB_ENABLE_LIBXML2=ON \ -DLLDB_ENABLE_LUA=OFF \ - -DLLDB_ENABLE_LZMA=OFF \ + -DLLVM_ENABLE_LZMA=OFF \ -DLLDB_ENABLE_PYTHON=ON \ -DLLDB_ENABLE_SWIG=ON \ -DLLVM_BUILD_TOOLS=TRUE \ diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 1cb20f5234bed6..1d0f197197fb1d 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -59,7 +59,6 @@ mark_as_advanced(LLDB_LIBXML2_VERSION) add_optional_dependency(LLDB_ENABLE_SWIG "Enable SWIG to generate LLDB bindings" SWIG SWIG_FOUND VERSION 4) add_optional_dependency(LLDB_ENABLE_LIBEDIT "Enable editline support in LLDB" LibEdit LibEdit_FOUND) add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" CursesAndPanel CURSESANDPANEL_FOUND) -add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND) add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND) add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND) add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION ${LLDB_LIBXML2_VERSION}) @@ -347,10 +346,6 @@ endif() set(LLDB_VERSION "${LLDB_VERSION_MAJOR}.${LLDB_VERSION_MINOR}.${LLDB_VERSION_PATCH}${LLDB_VERSION_SUFFIX}") message(STATUS "LLDB version: ${LLDB_VERSION}") -if (LLDB_ENABLE_LZMA) - include_directories(${LIBLZMA_INCLUDE_DIRS}) -endif() - include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include diff --git a/lldb/docs/resources/build.md b/lldb/docs/resources/build.md index e3c3250006051e..414b5519072123 100644 --- a/lldb/docs/resources/build.md +++ b/lldb/docs/resources/build.md @@ -50,7 +50,6 @@ CMake configuration error. | -------- | ---------------------------------------------------------- | --------------------- | | Editline | Generic line editing, history, Emacs and Vi bindings | `LLDB_ENABLE_LIBEDIT` | | Curses | Text user interface | `LLDB_ENABLE_CURSES` | -| LZMA | Lossless data compression | `LLDB_ENABLE_LZMA` | | Libxml2 | XML | `LLDB_ENABLE_LIBXML2` | | Python | Python scripting. 3.8 or later (3.11 or later on Windows). | `LLDB_ENABLE_PYTHON` | | Lua | Lua scripting. Lua 5.3 and 5.4 are supported. | `LLDB_ENABLE_LUA` | diff --git a/lldb/include/lldb/Host/Config.h.cmake b/lldb/include/lldb/Host/Config.h.cmake index 1cd8a6832702c4..efda80d4544fa7 100644 --- a/lldb/include/lldb/Host/Config.h.cmake +++ b/lldb/include/lldb/Host/Config.h.cmake @@ -29,8 +29,6 @@ #cmakedefine01 LLDB_ENABLE_TERMIOS -#cmakedefine01 LLDB_ENABLE_LZMA - #cmakedefine01 LLVM_ENABLE_CURL #cmakedefine01 LLDB_ENABLE_CURSES diff --git a/lldb/include/lldb/Host/LZMA.h b/lldb/include/lldb/Host/LZMA.h deleted file mode 100644 index 8dc69a8dc10e5e..00000000000000 --- a/lldb/include/lldb/Host/LZMA.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- LZMA.h --------------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_HOST_LZMA_H -#define LLDB_HOST_LZMA_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Error.h" - -namespace llvm { -class Error; -} // End of namespace llvm - -namespace lldb_private { - -namespace lzma { - -bool isAvailable(); - -llvm::Expected<uint64_t> -getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer); - -llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, - llvm::SmallVectorImpl<uint8_t> &Uncompressed); - -} // End of namespace lzma - -} // End of namespace lldb_private - -#endif // LLDB_HOST_LZMA_H diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 2f1d17598c76c2..231295d0b523d8 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -2622,7 +2622,7 @@ StructuredData::DictionarySP Debugger::GetBuildConfiguration() { *config_up, "zlib", LLVM_ENABLE_ZLIB, "A boolean value that indicates if zlib support is enabled in LLDB"); AddBoolConfigEntry( - *config_up, "lzma", LLDB_ENABLE_LZMA, + *config_up, "lzma", LLVM_ENABLE_LZMA, "A boolean value that indicates if lzma support is enabled in LLDB"); AddBoolConfigEntry( *config_up, "python", LLDB_ENABLE_PYTHON, diff --git a/lldb/source/Host/CMakeLists.txt b/lldb/source/Host/CMakeLists.txt index ebcad8f63e4f3d..6409c29fbb7c3c 100644 --- a/lldb/source/Host/CMakeLists.txt +++ b/lldb/source/Host/CMakeLists.txt @@ -30,7 +30,6 @@ add_host_subdirectory(common common/HostProcess.cpp common/HostThread.cpp common/JSONTransport.cpp - common/LZMA.cpp common/LockFileBase.cpp common/MainLoopBase.cpp common/MemoryMonitor.cpp @@ -195,9 +194,6 @@ endif() if (LLDB_ENABLE_LIBEDIT) list(APPEND EXTRA_LIBS LibEdit::LibEdit) endif() -if (LLDB_ENABLE_LZMA) - list(APPEND EXTRA_LIBS ${LIBLZMA_LIBRARIES}) -endif() if (WIN32) list(APPEND LLDB_SYSTEM_LIBS psapi) endif() diff --git a/lldb/source/Host/common/LZMA.cpp b/lldb/source/Host/common/LZMA.cpp deleted file mode 100644 index 5b457f07afca17..00000000000000 --- a/lldb/source/Host/common/LZMA.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===-- LZMA.cpp ----------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/Config.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" - -#if LLDB_ENABLE_LZMA -#include <lzma.h> -#endif // LLDB_ENABLE_LZMA - -namespace lldb_private { - -namespace lzma { - -#if !LLDB_ENABLE_LZMA -bool isAvailable() { return false; } -llvm::Expected<uint64_t> -getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { - llvm_unreachable("lzma::getUncompressedSize is unavailable"); -} - -llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, - llvm::SmallVectorImpl<uint8_t> &Uncompressed) { - llvm_unreachable("lzma::uncompress is unavailable"); -} - -#else // LLDB_ENABLE_LZMA - -bool isAvailable() { return true; } - -static const char *convertLZMACodeToString(lzma_ret Code) { - switch (Code) { - case LZMA_STREAM_END: - return "lzma error: LZMA_STREAM_END"; - case LZMA_NO_CHECK: - return "lzma error: LZMA_NO_CHECK"; - case LZMA_UNSUPPORTED_CHECK: - return "lzma error: LZMA_UNSUPPORTED_CHECK"; - case LZMA_GET_CHECK: - return "lzma error: LZMA_GET_CHECK"; - case LZMA_MEM_ERROR: - return "lzma error: LZMA_MEM_ERROR"; - case LZMA_MEMLIMIT_ERROR: - return "lzma error: LZMA_MEMLIMIT_ERROR"; - case LZMA_FORMAT_ERROR: - return "lzma error: LZMA_FORMAT_ERROR"; - case LZMA_OPTIONS_ERROR: - return "lzma error: LZMA_OPTIONS_ERROR"; - case LZMA_DATA_ERROR: - return "lzma error: LZMA_DATA_ERROR"; - case LZMA_BUF_ERROR: - return "lzma error: LZMA_BUF_ERROR"; - case LZMA_PROG_ERROR: - return "lzma error: LZMA_PROG_ERROR"; - default: - llvm_unreachable("unknown or unexpected lzma status code"); - } -} - -llvm::Expected<uint64_t> -getUncompressedSize(llvm::ArrayRef<uint8_t> InputBuffer) { - lzma_stream_flags opts{}; - if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "size of xz-compressed blob (%lu bytes) is smaller than the " - "LZMA_STREAM_HEADER_SIZE (%lu bytes)", - InputBuffer.size(), LZMA_STREAM_HEADER_SIZE); - } - - // Decode xz footer. - lzma_ret xzerr = lzma_stream_footer_decode( - &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); - if (xzerr != LZMA_OK) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "lzma_stream_footer_decode()=%s", - convertLZMACodeToString(xzerr)); - } - if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "xz-compressed buffer size (%lu bytes) too small (required at " - "least %lu bytes) ", - InputBuffer.size(), (opts.backward_size + LZMA_STREAM_HEADER_SIZE)); - } - - // Decode xz index. - lzma_index *xzindex; - uint64_t memlimit(UINT64_MAX); - size_t inpos = 0; - xzerr = lzma_index_buffer_decode( - &xzindex, &memlimit, nullptr, - InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE + opts.backward_size) - .data(), - &inpos, InputBuffer.size()); - if (xzerr != LZMA_OK) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "lzma_index_buffer_decode()=%s", - convertLZMACodeToString(xzerr)); - } - - // Get size of uncompressed file to construct an in-memory buffer of the - // same size on the calling end (if needed). - uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); - - // Deallocate xz index as it is no longer needed. - lzma_index_end(xzindex, nullptr); - - return uncompressedSize; -} - -llvm::Error uncompress(llvm::ArrayRef<uint8_t> InputBuffer, - llvm::SmallVectorImpl<uint8_t> &Uncompressed) { - llvm::Expected<uint64_t> uncompressedSize = getUncompressedSize(InputBuffer); - - if (auto err = uncompressedSize.takeError()) - return err; - - Uncompressed.resize(*uncompressedSize); - - // Decompress xz buffer to buffer. - uint64_t memlimit = UINT64_MAX; - size_t inpos = 0; - size_t outpos = 0; - lzma_ret ret = lzma_stream_buffer_decode( - &memlimit, 0, nullptr, InputBuffer.data(), &inpos, InputBuffer.size(), - Uncompressed.data(), &outpos, Uncompressed.size()); - if (ret != LZMA_OK) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "lzma_stream_buffer_decode()=%s", - convertLZMACodeToString(ret)); - } - - return llvm::Error::success(); -} - -#endif // LLDB_ENABLE_LZMA - -} // end of namespace lzma -} // namespace lldb_private diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 12739c17c0b653..ccb168c5b810d4 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -20,7 +20,6 @@ #include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Host/FileSystem.h" -#include "lldb/Host/LZMA.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Process.h" @@ -44,6 +43,7 @@ #include "llvm/Object/Decompressor.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/CRC.h" +#include "llvm/Support/Compression.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -2219,7 +2219,7 @@ std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() { if (!section) return nullptr; - if (!lldb_private::lzma::isAvailable()) { + if (!llvm::compression::xz::isAvailable()) { GetModule()->ReportWarning( "no LZMA support found for reading .gnu_debugdata section"); return nullptr; @@ -2229,7 +2229,8 @@ std::shared_ptr<ObjectFileELF> ObjectFileELF::GetGnuDebugDataObjectFile() { DataExtractor data; section->GetSectionData(data); llvm::SmallVector<uint8_t, 0> uncompressedData; - auto err = lldb_private::lzma::uncompress(data.GetData(), uncompressedData); + auto err = + llvm::compression::xz::decompress(data.GetData(), uncompressedData); if (err) { GetModule()->ReportWarning( "an error occurred while decompressing the section {0}: {1}", diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index c79f05cf85841a..db93ea5f948167 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -294,7 +294,7 @@ llvm_canonicalize_cmake_booleans( LLDB_ENABLE_MTE LLDB_ENABLE_PYTHON LLDB_ENABLE_LUA - LLDB_ENABLE_LZMA + LLVM_ENABLE_LZMA LLVM_ENABLE_ZLIB LLVM_ENABLE_SHARED_LIBS LLVM_ENABLE_DIA_SDK diff --git a/lldb/test/Shell/lit.cfg.py b/lldb/test/Shell/lit.cfg.py index 134dba7f1c494f..ca21ac00e6d6d5 100644 --- a/lldb/test/Shell/lit.cfg.py +++ b/lldb/test/Shell/lit.cfg.py @@ -145,9 +145,6 @@ def calculate_arch_features(arch_string): if config.lldb_enable_lua: config.available_features.add("lua") -if config.lldb_enable_lzma: - config.available_features.add("lzma") - if shutil.which("xz") is not None: config.available_features.add("xz") diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in index 68c94cd4ee3b24..aa5d151987a901 100644 --- a/lldb/test/Shell/lit.site.cfg.py.in +++ b/lldb/test/Shell/lit.site.cfg.py.in @@ -24,7 +24,7 @@ config.python_executable = "@Python3_EXECUTABLE@" config.python_root_dir = "@Python3_ROOT_DIR@" config.have_zlib = @LLVM_ENABLE_ZLIB@ config.objc_gnustep_dir = "@LLDB_TEST_OBJC_GNUSTEP_DIR@" -config.lldb_enable_lzma = @LLDB_ENABLE_LZMA@ +config.have_lzma = @LLVM_ENABLE_LZMA@ config.host_triple = "@LLVM_HOST_TRIPLE@" config.lldb_bitness = 64 if @LLDB_IS_64_BITS@ else 32 config.lldb_enable_python = @LLDB_ENABLE_PYTHON@ diff --git a/llvm/utils/gn/secondary/lldb/include/lldb/Host/BUILD.gn b/llvm/utils/gn/secondary/lldb/include/lldb/Host/BUILD.gn index dbb8d82823ff9e..bf3f19284b33fd 100644 --- a/llvm/utils/gn/secondary/lldb/include/lldb/Host/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/include/lldb/Host/BUILD.gn @@ -15,7 +15,6 @@ write_cmake_config("Config") { "LLDB_HAVE_EL_RFUNC_T=", "HAVE_PTSNAME_R=", "HAVE_NR_PROCESS_VM_READV=", - "LLDB_ENABLE_LZMA=", "LLDB_ENABLE_CURSES=", "CURSES_HAVE_NCURSES_CURSES_H=", "LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS=", diff --git a/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn b/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn index 4c0ea2ff7e9a52..85556ed155f0c4 100644 --- a/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/source/Host/BUILD.gn @@ -29,7 +29,6 @@ static_library("Host") { "common/HostProcess.cpp", "common/HostThread.cpp", "common/JSONTransport.cpp", - "common/LZMA.cpp", "common/LockFileBase.cpp", "common/MainLoopBase.cpp", "common/MemoryMonitor.cpp", @@ -170,9 +169,6 @@ static_library("Host") { # if (LLDB_ENABLE_LIBEDIT) # list(APPEND EXTRA_LIBS LibEdit::LibEdit) # endif() - # if (LLDB_ENABLE_LZMA) - # list(APPEND EXTRA_LIBS ${LIBLZMA_LIBRARIES}) - # endif() # if (WIN32) # list(APPEND LLDB_SYSTEM_LIBS psapi) # endif() diff --git a/llvm/utils/gn/secondary/lldb/test/BUILD.gn b/llvm/utils/gn/secondary/lldb/test/BUILD.gn index 000ce97b1e6e9a..53fdeddaf17814 100644 --- a/llvm/utils/gn/secondary/lldb/test/BUILD.gn +++ b/llvm/utils/gn/secondary/lldb/test/BUILD.gn @@ -141,7 +141,7 @@ write_lit_cfg("lit_shell_site_cfg") { "LIBCXX_LIBRARY_DIR=" + rebase_path("$root_build_dir/lib"), "LLDB_BUILD_LLDBRPC=0", # FIXME: add lldb-rpc-gen target, enable "LLDB_ENABLE_LUA=0", # FIXME: gn arg, use in Config.h - "LLDB_ENABLE_LZMA=0", # FIXME: gn arg, use in Config.h + "LLVM_ENABLE_LZMA=0", # FIXME: gn arg, use in llvm-config.h "LLDB_ENABLE_MTE=0", "LLDB_ENABLE_PYTHON=0", # FIXME: gn arg, use in Config.h "LLDB_HAS_LIBCXX=False", # FIXME: support this (?) diff --git a/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel b/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel index 8bd2dd37d5394e..46cdd73da6a4f6 100644 --- a/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/lldb/BUILD.bazel @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception load("@bazel_skylib//lib:selects.bzl", "selects") -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag", "string_flag") +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") load("@bazel_skylib//rules:expand_template.bzl", "expand_template") load("@build_bazel_apple_support//rules:apple_genrule.bzl", "apple_genrule") load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", "objc_library") @@ -70,20 +70,6 @@ selects.config_setting_group( ], ) -string_flag( - name = "lzma", - build_setting_default = "disable", - values = [ - "disable", - "system", - ], -) - -config_setting( - name = "system_lzma_enabled", - flag_values = {":lzma": "system"}, -) - _VERSION_SUBSTITUTIONS = { "@LLDB_VERSION@": PACKAGE_VERSION, "@LLDB_VERSION_MAJOR@": LLVM_VERSION_MAJOR, @@ -218,13 +204,6 @@ expand_template( "#cmakedefine01 LLDB_EDITLINE_USE_WCHAR": "#define LLDB_EDITLINE_USE_WCHAR 0", "#cmakedefine01 LLDB_ENABLE_LIBEDIT": "#define LLDB_ENABLE_LIBEDIT 0", }, - }) | select({ - ":system_lzma_enabled": { - "#cmakedefine01 LLDB_ENABLE_LZMA": "#define LLDB_ENABLE_LZMA 1", - }, - "//conditions:default": { - "#cmakedefine01 LLDB_ENABLE_LZMA": "#define LLDB_ENABLE_LZMA 0", - }, }), template = "include/lldb/Host/Config.h.cmake", ) @@ -684,11 +663,6 @@ cc_library( "-lbsd", ], "//conditions:default": [], - }) + select({ - ":system_lzma_enabled": [ - "-llzma", - ], - "//conditions:default": [], }), deps = [ ":Headers", >From 3d07a1047ad22a7e0ee924fd9600adb7ba3992a3 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 9 Sep 2026 14:01:16 -0700 Subject: [PATCH 4/6] Address review comments on compression::xz Own the lzma_index with a scope_exit so it is released on every path out of getUncompressedSize(), and initialize it to null. Correct the minimum-size check: a stream is a header, the blocks, the index and a footer the same size as the header, so the floor is backward_size plus two header sizes, not one. Reject an index-declared size that does not fit in size_t, drop a trailing space from the "buffer size too small" diagnostic, and guarantee Output is empty whenever an error is returned. Split the error cases into their own test, covering a truncated index and a corrupt index CRC32 that were not previously exercised. --- llvm/include/llvm/Support/Compression.h | 3 +- llvm/lib/Support/Compression.cpp | 39 +++++++---- llvm/unittests/Support/CompressionTest.cpp | 79 ++++++++++++++-------- 3 files changed, 78 insertions(+), 43 deletions(-) diff --git a/llvm/include/llvm/Support/Compression.h b/llvm/include/llvm/Support/Compression.h index 06188af2526e60..3cfee87dceab86 100644 --- a/llvm/include/llvm/Support/Compression.h +++ b/llvm/include/llvm/Support/Compression.h @@ -83,7 +83,8 @@ LLVM_ABI bool isAvailable(); /// Decompress an xz stream. Unlike zlib and zstd, the uncompressed size does /// not need to be supplied by the caller: it is recovered from the stream -/// index, and \p Output is resized to fit. +/// index, and \p Output is resized to fit. \p Output is left empty if an error +/// is returned. /// /// Requires isAvailable(); calling this otherwise is a fatal error. LLVM_ABI Error decompress(ArrayRef<uint8_t> Input, diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp index 9337fc2cf23688..0d4d3b007a33f4 100644 --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -11,12 +11,14 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Compression.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include <limits> #if LLVM_ENABLE_ZLIB #include <zlib.h> #endif @@ -299,17 +301,20 @@ static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> InputBuffer) { "lzma_stream_footer_decode()=%s", convertLZMACodeToString(xzerr)); } - if (InputBuffer.size() < (opts.backward_size + LZMA_STREAM_HEADER_SIZE)) { + // A stream is the header, block data, index and stream footer + uint64_t minSize = opts.backward_size + 2 * LZMA_STREAM_HEADER_SIZE; + if (InputBuffer.size() < minSize) { return createStringError( inconvertibleErrorCode(), "xz-compressed buffer size (%zu bytes) too small (required at " - "least %" PRIu64 " bytes) ", - InputBuffer.size(), - uint64_t(opts.backward_size + LZMA_STREAM_HEADER_SIZE)); + "least %" PRIu64 " bytes)", + InputBuffer.size(), minSize); } // Decode xz index. - lzma_index *xzindex; + // liblzma stores null on failure, and lzma_index_end() ignores null. + lzma_index *xzindex = nullptr; + llvm::scope_exit freeIndex([&] { lzma_index_end(xzindex, nullptr); }); uint64_t memlimit(UINT64_MAX); size_t inpos = 0; ArrayRef<uint8_t> IndexBuffer = InputBuffer.drop_back(LZMA_STREAM_HEADER_SIZE) @@ -323,24 +328,29 @@ static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> InputBuffer) { convertLZMACodeToString(xzerr)); } - // Get size of uncompressed file to construct an in-memory buffer of the - // same size on the calling end (if needed). - uint64_t uncompressedSize = lzma_index_uncompressed_size(xzindex); - - // Deallocate xz index as it is no longer needed. - lzma_index_end(xzindex, nullptr); - - return uncompressedSize; + return lzma_index_uncompressed_size(xzindex); } Error xz::decompress(ArrayRef<uint8_t> Input, SmallVectorImpl<uint8_t> &Output) { + // Hand back nothing unless the whole stream decodes. + Output.clear(); + Expected<uint64_t> uncompressedSize = getUncompressedSize(Input); if (auto err = uncompressedSize.takeError()) return err; - Output.resize(*uncompressedSize); + if (*uncompressedSize > std::numeric_limits<size_t>::max()) { + return createStringError(inconvertibleErrorCode(), + "xz uncompressed size (%" PRIu64 + " bytes) exceeds addressable memory", + *uncompressedSize); + } + + // Concatenated streams are unsupported: liblzma decodes only the first and + // still reports LZMA_OK, leaving the rest of Output zero-filled. + Output.resize(static_cast<size_t>(*uncompressedSize)); // Decompress xz buffer to buffer. uint64_t memlimit = UINT64_MAX; @@ -350,6 +360,7 @@ Error xz::decompress(ArrayRef<uint8_t> Input, &inpos, Input.size(), Output.data(), &outpos, Output.size()); if (ret != LZMA_OK) { + Output.clear(); return createStringError(inconvertibleErrorCode(), "lzma_stream_buffer_decode()=%s", convertLZMACodeToString(ret)); diff --git a/llvm/unittests/Support/CompressionTest.cpp b/llvm/unittests/Support/CompressionTest.cpp index 508ceb5ab671ab..df6b4540251b4f 100644 --- a/llvm/unittests/Support/CompressionTest.cpp +++ b/llvm/unittests/Support/CompressionTest.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" #include "llvm/Support/Error.h" +#include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; @@ -114,10 +115,8 @@ TEST(CompressionTest, Zstd) { #if LLVM_ENABLE_LZMA -// LLVM implements xz decompression but not compression, so these are -// checked-in literals rather than round trips. - -/// `xz --check=crc32 -9` of the empty string. +/// `xz --check=crc32 -9` of the empty string. LLVM implements xz decompression +/// but not compression, so the fixtures are literals rather than round trips. static constexpr uint8_t XzEmptyData[] = { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00, 0x00, 0x01, 0x69, 0x22, 0xde, 0x36, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xdf, 0x44, 0x21, 0x90, 0x42, @@ -134,35 +133,25 @@ static constexpr uint8_t XzTextData[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5a, }; +// A stream is a header, the blocks, the index, and a footer of the same size. +static constexpr size_t XzStreamHeaderSize = 12; +static constexpr size_t XzStreamFooterSize = 12; + static void testXzDecompression(ArrayRef<uint8_t> Compressed, StringRef Expected) { + // The uncompressed size comes from the stream index, not from the caller. SmallVector<uint8_t, 0> Uncompressed; - - // Check that uncompressed buffer is the same as original. The uncompressed - // size is recovered from the stream index, not supplied by the caller. - Error E = xz::decompress(Compressed, Uncompressed); - EXPECT_FALSE(std::move(E)); + ASSERT_THAT_ERROR(xz::decompress(Compressed, Uncompressed), Succeeded()); EXPECT_EQ(Expected, toStringRef(Uncompressed)); +} - // Decompression fails if the buffer is too small to hold a stream header. - E = xz::decompress(Compressed.take_front(4), Uncompressed); - EXPECT_EQ("size of xz-compressed blob (4 bytes) is smaller than the " - "LZMA_STREAM_HEADER_SIZE (12 bytes)", - llvm::toString(std::move(E))); - - // Decompression fails if the footer holding the uncompressed size is gone. - E = xz::decompress(Compressed.drop_back(4), Uncompressed); - EXPECT_EQ("lzma_stream_footer_decode()=lzma error: LZMA_FORMAT_ERROR", - llvm::toString(std::move(E))); - - if (!Expected.empty()) { - // Decompression fails if the compressed payload is corrupt. - SmallVector<uint8_t, 0> Corrupt(Compressed.begin(), Compressed.end()); - Corrupt[24] ^= 0xff; - E = xz::decompress(Corrupt, Uncompressed); - EXPECT_EQ("lzma_stream_buffer_decode()=lzma error: LZMA_DATA_ERROR", - llvm::toString(std::move(E))); - } +static std::string xzDecompressError(ArrayRef<uint8_t> Input) { + // Prefilled, both to prove a failure empties it and so that no case can + // observe what an earlier one left behind. + SmallVector<uint8_t, 0> Output(8, 0xaa); + std::string Message = llvm::toString(xz::decompress(Input, Output)); + EXPECT_TRUE(Output.empty()); + return Message; } TEST(CompressionTest, Xz) { @@ -171,5 +160,39 @@ TEST(CompressionTest, Xz) { testXzDecompression(XzEmptyData, ""); testXzDecompression(XzTextData, "hello, world!"); } + +TEST(CompressionTest, XzDecompressErrors) { + ArrayRef<uint8_t> Compressed(XzTextData); + auto FlipByte = [&](size_t Offset) { + SmallVector<uint8_t, 0> Corrupt(Compressed); + Corrupt[Offset] ^= 0xff; + return Corrupt; + }; + + // Too small to hold a stream header. + EXPECT_EQ("size of xz-compressed blob (4 bytes) is smaller than the " + "LZMA_STREAM_HEADER_SIZE (12 bytes)", + xzDecompressError(Compressed.take_front(4))); + + // The footer recording where the index lives is gone. + EXPECT_EQ("lzma_stream_footer_decode()=lzma error: LZMA_FORMAT_ERROR", + xzDecompressError(Compressed.drop_back(4))); + + // The footer is intact but the index it points back to has been cut off. + EXPECT_EQ("xz-compressed buffer size (12 bytes) too small (required at " + "least 32 bytes)", + xzDecompressError(Compressed.take_back(XzStreamFooterSize))); + + // The index's CRC32, in the four bytes just before the footer, is corrupt. + size_t IndexCrcOffset = Compressed.size() - XzStreamFooterSize - 1; + EXPECT_EQ("lzma_index_buffer_decode()=lzma error: LZMA_DATA_ERROR", + xzDecompressError(FlipByte(IndexCrcOffset))); + + // The payload is corrupt. It follows the stream header and the block header, + // whose length in four-byte units is held in its first byte. + size_t BlockHeaderSize = (Compressed[XzStreamHeaderSize] + 1) * 4; + EXPECT_EQ("lzma_stream_buffer_decode()=lzma error: LZMA_DATA_ERROR", + xzDecompressError(FlipByte(XzStreamHeaderSize + BlockHeaderSize))); +} #endif } // namespace >From 3eb76470fef48ae89414888411f8294d25417e26 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 9 Sep 2026 14:01:18 -0700 Subject: [PATCH 5/6] Deprecate LLDB_ENABLE_LZMA in favor of LLVM_ENABLE_LZMA liblzma is now found by LLVM, so LLDB_ENABLE_LZMA has nothing left to control. Rather than dropping it and silently reinterpreting existing configurations, llvm/CMakeLists.txt maps it onto LLVM_ENABLE_LZMA before config-ix runs, so it still seeds the value LLVMSupport is compiled with: Auto -> ON, On -> FORCE_ON (On meant REQUIRED), Off -> OFF. An explicit LLVM_ENABLE_LZMA wins, and only the default is seeded, so already-configured build directories are unaffected. Remove the shim once release/24.x has branched. A standalone LLDB build links a prebuilt LLVM and cannot change what it was built with, so LLDBConfig.cmake only reports the ignored setting. It also restores the status line that add_optional_dependency() used to print, so LZMA still shows up alongside the other optional dependencies. Neither message fires for Auto: that was the old default, so every build directory predating this change carries it without anyone having asked for it, and it maps onto the new default anyway. Warning there would be noise, and under CMAKE_ERROR_DEPRECATED a configure failure for a value nobody chose. --- lldb/cmake/modules/LLDBConfig.cmake | 14 ++++++++++++++ llvm/CMakeLists.txt | 20 +++++++++++++++++++- llvm/docs/ReleaseNotes.md | 9 +++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 1d0f197197fb1d..2b4b36a6fb7319 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -64,6 +64,20 @@ add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in L add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION ${LLDB_LIBXML2_VERSION}) add_optional_dependency(LLDB_ENABLE_TREESITTER "Enable Tree-sitter syntax highlighting" TreeSitter TREESITTER_FOUND) +# liblzma comes from LLVM, and a standalone build cannot change how LLVM was +# built, so LLDB_ENABLE_LZMA can only be reported here. +if(LLDB_BUILT_STANDALONE AND DEFINED LLDB_ENABLE_LZMA) + string(TOUPPER "${LLDB_ENABLE_LZMA}" lldb_enable_lzma) + if(NOT lldb_enable_lzma STREQUAL "AUTO") + message(DEPRECATION + "LLDB_ENABLE_LZMA is deprecated and has no effect in a standalone build. " + "liblzma comes from LLVM, which was built with " + "LLVM_ENABLE_LZMA=${LLVM_ENABLE_LZMA}.") + endif() + unset(lldb_enable_lzma) +endif() +message(STATUS "Enable LZMA compression support in LLDB: ${LLVM_ENABLE_LZMA}") + option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON) option(LLDB_BUILD_FRAMEWORK "Build LLDB.framework (Darwin only)" OFF) option(LLDB_ENABLE_PROTOCOL_SERVERS "Enable protocol servers (e.g. MCP) in LLDB" ON) diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index 5893c8d6411a33..63df879080abf8 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -676,7 +676,25 @@ set(LLVM_ENABLE_ZSTD "ON" CACHE STRING "Use zstd for compression/decompression i set(LLVM_USE_STATIC_ZSTD FALSE CACHE BOOL "Use static version of zstd. Can be TRUE, FALSE") -set(LLVM_ENABLE_LZMA "ON" CACHE STRING "Use liblzma for xz decompression if available. Can be ON, OFF, or FORCE_ON") +# liblzma is an LLVM dependency now, so temporarily translate LLDB's older +# LLDB_ENABLE_LZMA; its On meant required, hence FORCE_ON. +set(LLVM_ENABLE_LZMA_DEFAULT "ON") +if(DEFINED LLDB_ENABLE_LZMA) + string(TOUPPER "${LLDB_ENABLE_LZMA}" lldb_enable_lzma) + if(NOT lldb_enable_lzma STREQUAL "AUTO") + message(DEPRECATION + "LLDB_ENABLE_LZMA is deprecated. Set LLVM_ENABLE_LZMA (ON, OFF or " + "FORCE_ON) instead; liblzma is now found by LLVM, not by LLDB.") + if(lldb_enable_lzma) + set(LLVM_ENABLE_LZMA_DEFAULT "FORCE_ON") + else() + set(LLVM_ENABLE_LZMA_DEFAULT "OFF") + endif() + endif() + unset(lldb_enable_lzma) +endif() +set(LLVM_ENABLE_LZMA "${LLVM_ENABLE_LZMA_DEFAULT}" CACHE STRING "Use liblzma for xz decompression if available. Can be ON, OFF, or FORCE_ON") +unset(LLVM_ENABLE_LZMA_DEFAULT) set(LLVM_ENABLE_CURL "OFF" CACHE STRING "Use libcurl for the HTTP client if available. Can be ON, OFF, or FORCE_ON") diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index ef90a1f1f1c41d..6124e75fd707b5 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -146,6 +146,11 @@ Makes programs 10x faster by doing Special New Thing. ### Changes to building LLVM +* A new `LLVM_ENABLE_LZMA` option (`ON`, `OFF` or `FORCE_ON`; default `ON`) + controls whether LLVM links liblzma for xz decompression. It replaces LLDB's + `LLDB_ENABLE_LZMA`, which is deprecated: a monorepo build maps it onto + `LLVM_ENABLE_LZMA`, and it has no effect in a standalone LLDB build. + * The DirectX backend is now an official target and has moved from `LLVM_ALL_EXPERIMENTAL_TARGETS` to `LLVM_ALL_TARGETS`. It is now built by default and no longer requires `LLVM_EXPERIMENTAL_TARGETS_TO_BUILD`. @@ -245,6 +250,10 @@ Makes programs 10x faster by doing Special New Thing. ### Changes to LLDB +* MiniDebugInfo (the ELF `.gnu_debugdata` section) is now decompressed by LLVM + rather than by LLDB's own liblzma binding, and is enabled with + `LLVM_ENABLE_LZMA` instead of the deprecated `LLDB_ENABLE_LZMA`. + #### SBAPI * A [bug](https://github.com/llvm/llvm-project/issues/211787) involving SBValues >From a80debe5799bf1664d3a51690a5b6888f21d65f1 Mon Sep 17 00:00:00 2001 From: Janet Yang <[email protected]> Date: Wed, 9 Sep 2026 14:01:18 -0700 Subject: [PATCH 6/6] [NFC] Adopt LLVM naming and error-reporting style in compression::xz The xz code was moved over from lldb_private::lzma, so its locals still use LLDB's lowercase spelling: xzerr, opts, memlimit, inpos, outpos. Rename them to match the LLVM naming convention now that the code lives in Support, drop the redundant inconvertibleErrorCode() argument that createStringError() supplies by default, and remove braces from single-statement branches. Kept separate from the functional changes it follows so those are easier to read. --- llvm/lib/Support/Compression.cpp | 102 ++++++++++++++----------------- 1 file changed, 45 insertions(+), 57 deletions(-) diff --git a/llvm/lib/Support/Compression.cpp b/llvm/lib/Support/Compression.cpp index 0d4d3b007a33f4..08a3f2b8a99f6b 100644 --- a/llvm/lib/Support/Compression.cpp +++ b/llvm/lib/Support/Compression.cpp @@ -283,52 +283,46 @@ static const char *convertLZMACodeToString(lzma_ret Code) { } } -static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> InputBuffer) { - lzma_stream_flags opts{}; - if (InputBuffer.size() < LZMA_STREAM_HEADER_SIZE) { +/// Read the uncompressed size recorded in the xz stream's index. +static Expected<uint64_t> getUncompressedSize(ArrayRef<uint8_t> Input) { + if (Input.size() < LZMA_STREAM_HEADER_SIZE) return createStringError( - inconvertibleErrorCode(), "size of xz-compressed blob (%zu bytes) is smaller than the " "LZMA_STREAM_HEADER_SIZE (%zu bytes)", - InputBuffer.size(), size_t(LZMA_STREAM_HEADER_SIZE)); - } + Input.size(), size_t(LZMA_STREAM_HEADER_SIZE)); + + // Decode the xz footer. + lzma_stream_flags FooterFlags{}; + lzma_ret Ret = lzma_stream_footer_decode( + &FooterFlags, Input.take_back(LZMA_STREAM_HEADER_SIZE).data()); + if (Ret != LZMA_OK) + return createStringError("lzma_stream_footer_decode()=%s", + convertLZMACodeToString(Ret)); - // Decode xz footer. - lzma_ret xzerr = lzma_stream_footer_decode( - &opts, InputBuffer.take_back(LZMA_STREAM_HEADER_SIZE).data()); - if (xzerr != LZMA_OK) { - return createStringError(inconvertibleErrorCode(), - "lzma_stream_footer_decode()=%s", - convertLZMACodeToString(xzerr)); - } // A stream is the header, block data, index and stream footer - uint64_t minSize = opts.backward_size + 2 * LZMA_STREAM_HEADER_SIZE; - if (InputBuffer.size() < minSize) { + uint64_t MinSize = FooterFlags.backward_size + 2 * LZMA_STREAM_HEADER_SIZE; + if (Input.size() < MinSize) return createStringError( - inconvertibleErrorCode(), "xz-compressed buffer size (%zu bytes) too small (required at " "least %" PRIu64 " bytes)", - InputBuffer.size(), minSize); - } + Input.size(), MinSize); // Decode xz index. + ArrayRef<uint8_t> IndexBuffer = + Input.drop_back(LZMA_STREAM_HEADER_SIZE) + .take_back(size_t(FooterFlags.backward_size)); // liblzma stores null on failure, and lzma_index_end() ignores null. - lzma_index *xzindex = nullptr; - llvm::scope_exit freeIndex([&] { lzma_index_end(xzindex, nullptr); }); - uint64_t memlimit(UINT64_MAX); - size_t inpos = 0; - ArrayRef<uint8_t> IndexBuffer = InputBuffer.drop_back(LZMA_STREAM_HEADER_SIZE) - .take_back(opts.backward_size); - xzerr = - lzma_index_buffer_decode(&xzindex, &memlimit, nullptr, IndexBuffer.data(), - &inpos, IndexBuffer.size()); - if (xzerr != LZMA_OK) { - return createStringError(inconvertibleErrorCode(), - "lzma_index_buffer_decode()=%s", - convertLZMACodeToString(xzerr)); - } - - return lzma_index_uncompressed_size(xzindex); + lzma_index *Index = nullptr; + llvm::scope_exit FreeIndex([&] { lzma_index_end(Index, nullptr); }); + uint64_t MemLimit = UINT64_MAX; + size_t InPos = 0; + Ret = lzma_index_buffer_decode(&Index, &MemLimit, nullptr, IndexBuffer.data(), + &InPos, IndexBuffer.size()); + if (Ret != LZMA_OK) + return createStringError("lzma_index_buffer_decode()=%s", + convertLZMACodeToString(Ret)); + + return lzma_index_uncompressed_size(Index); } Error xz::decompress(ArrayRef<uint8_t> Input, @@ -336,34 +330,28 @@ Error xz::decompress(ArrayRef<uint8_t> Input, // Hand back nothing unless the whole stream decodes. Output.clear(); - Expected<uint64_t> uncompressedSize = getUncompressedSize(Input); + Expected<uint64_t> UncompressedSize = getUncompressedSize(Input); + if (!UncompressedSize) + return UncompressedSize.takeError(); - if (auto err = uncompressedSize.takeError()) - return err; - - if (*uncompressedSize > std::numeric_limits<size_t>::max()) { - return createStringError(inconvertibleErrorCode(), - "xz uncompressed size (%" PRIu64 + if (*UncompressedSize > std::numeric_limits<size_t>::max()) + return createStringError("xz uncompressed size (%" PRIu64 " bytes) exceeds addressable memory", - *uncompressedSize); - } + *UncompressedSize); // Concatenated streams are unsupported: liblzma decodes only the first and // still reports LZMA_OK, leaving the rest of Output zero-filled. - Output.resize(static_cast<size_t>(*uncompressedSize)); - - // Decompress xz buffer to buffer. - uint64_t memlimit = UINT64_MAX; - size_t inpos = 0; - size_t outpos = 0; - lzma_ret ret = lzma_stream_buffer_decode(&memlimit, 0, nullptr, Input.data(), - &inpos, Input.size(), Output.data(), - &outpos, Output.size()); - if (ret != LZMA_OK) { + Output.resize(static_cast<size_t>(*UncompressedSize)); + uint64_t MemLimit = UINT64_MAX; + size_t InPos = 0; + size_t OutPos = 0; + lzma_ret Ret = lzma_stream_buffer_decode( + &MemLimit, /*flags=*/0, nullptr, Input.data(), &InPos, Input.size(), + Output.data(), &OutPos, Output.size()); + if (Ret != LZMA_OK) { Output.clear(); - return createStringError(inconvertibleErrorCode(), - "lzma_stream_buffer_decode()=%s", - convertLZMACodeToString(ret)); + return createStringError("lzma_stream_buffer_decode()=%s", + convertLZMACodeToString(Ret)); } return Error::success(); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
