245 lines · cpp
1//===--- Compression.cpp - Compression implementation ---------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements compression functions.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Support/Compression.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/ADT/StringRef.h"16#include "llvm/Config/config.h"17#include "llvm/Support/Compiler.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/ErrorHandling.h"20#if LLVM_ENABLE_ZLIB21#include <zlib.h>22#endif23#if LLVM_ENABLE_ZSTD24#include <zstd.h>25#endif26 27using namespace llvm;28using namespace llvm::compression;29 30const char *compression::getReasonIfUnsupported(compression::Format F) {31 switch (F) {32 case compression::Format::Zlib:33 if (zlib::isAvailable())34 return nullptr;35 return "LLVM was not built with LLVM_ENABLE_ZLIB or did not find zlib at "36 "build time";37 case compression::Format::Zstd:38 if (zstd::isAvailable())39 return nullptr;40 return "LLVM was not built with LLVM_ENABLE_ZSTD or did not find zstd at "41 "build time";42 }43 llvm_unreachable("");44}45 46void compression::compress(Params P, ArrayRef<uint8_t> Input,47 SmallVectorImpl<uint8_t> &Output) {48 switch (P.format) {49 case compression::Format::Zlib:50 zlib::compress(Input, Output, P.level);51 break;52 case compression::Format::Zstd:53 zstd::compress(Input, Output, P.level, P.zstdEnableLdm);54 break;55 }56}57 58Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,59 uint8_t *Output, size_t UncompressedSize) {60 switch (formatFor(T)) {61 case compression::Format::Zlib:62 return zlib::decompress(Input, Output, UncompressedSize);63 case compression::Format::Zstd:64 return zstd::decompress(Input, Output, UncompressedSize);65 }66 llvm_unreachable("");67}68 69Error compression::decompress(compression::Format F, ArrayRef<uint8_t> Input,70 SmallVectorImpl<uint8_t> &Output,71 size_t UncompressedSize) {72 switch (F) {73 case compression::Format::Zlib:74 return zlib::decompress(Input, Output, UncompressedSize);75 case compression::Format::Zstd:76 return zstd::decompress(Input, Output, UncompressedSize);77 }78 llvm_unreachable("");79}80 81Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input,82 SmallVectorImpl<uint8_t> &Output,83 size_t UncompressedSize) {84 return decompress(formatFor(T), Input, Output, UncompressedSize);85}86 87#if LLVM_ENABLE_ZLIB88 89static StringRef convertZlibCodeToString(int Code) {90 switch (Code) {91 case Z_MEM_ERROR:92 return "zlib error: Z_MEM_ERROR";93 case Z_BUF_ERROR:94 return "zlib error: Z_BUF_ERROR";95 case Z_STREAM_ERROR:96 return "zlib error: Z_STREAM_ERROR";97 case Z_DATA_ERROR:98 return "zlib error: Z_DATA_ERROR";99 case Z_OK:100 default:101 llvm_unreachable("unknown or unexpected zlib status code");102 }103}104 105bool zlib::isAvailable() { return true; }106 107void zlib::compress(ArrayRef<uint8_t> Input,108 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {109 unsigned long CompressedSize = ::compressBound(Input.size());110 CompressedBuffer.resize_for_overwrite(CompressedSize);111 int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,112 (const Bytef *)Input.data(), Input.size(), Level);113 if (Res == Z_MEM_ERROR)114 report_bad_alloc_error("Allocation failed");115 assert(Res == Z_OK);116 // Tell MemorySanitizer that zlib output buffer is fully initialized.117 // This avoids a false report when running LLVM with uninstrumented ZLib.118 __msan_unpoison(CompressedBuffer.data(), CompressedSize);119 if (CompressedSize < CompressedBuffer.size())120 CompressedBuffer.truncate(CompressedSize);121}122 123Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,124 size_t &UncompressedSize) {125 int Res = ::uncompress((Bytef *)Output, (uLongf *)&UncompressedSize,126 (const Bytef *)Input.data(), Input.size());127 // Tell MemorySanitizer that zlib output buffer is fully initialized.128 // This avoids a false report when running LLVM with uninstrumented ZLib.129 __msan_unpoison(Output, UncompressedSize);130 return Res ? make_error<StringError>(convertZlibCodeToString(Res),131 inconvertibleErrorCode())132 : Error::success();133}134 135Error zlib::decompress(ArrayRef<uint8_t> Input,136 SmallVectorImpl<uint8_t> &Output,137 size_t UncompressedSize) {138 Output.resize_for_overwrite(UncompressedSize);139 Error E = zlib::decompress(Input, Output.data(), UncompressedSize);140 if (UncompressedSize < Output.size())141 Output.truncate(UncompressedSize);142 return E;143}144 145#else146bool zlib::isAvailable() { return false; }147void zlib::compress(ArrayRef<uint8_t> Input,148 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {149 llvm_unreachable("zlib::compress is unavailable");150}151Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,152 size_t &UncompressedSize) {153 llvm_unreachable("zlib::decompress is unavailable");154}155Error zlib::decompress(ArrayRef<uint8_t> Input,156 SmallVectorImpl<uint8_t> &UncompressedBuffer,157 size_t UncompressedSize) {158 llvm_unreachable("zlib::decompress is unavailable");159}160#endif161 162#if LLVM_ENABLE_ZSTD163 164bool zstd::isAvailable() { return true; }165 166#include <zstd.h> // Ensure ZSTD library is included167 168void zstd::compress(ArrayRef<uint8_t> Input,169 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,170 bool EnableLdm) {171 ZSTD_CCtx *Cctx = ZSTD_createCCtx();172 if (!Cctx)173 report_bad_alloc_error("Failed to create ZSTD_CCtx");174 175 if (ZSTD_isError(ZSTD_CCtx_setParameter(176 Cctx, ZSTD_c_enableLongDistanceMatching, EnableLdm ? 1 : 0))) {177 ZSTD_freeCCtx(Cctx);178 report_bad_alloc_error("Failed to set ZSTD_c_enableLongDistanceMatching");179 }180 181 if (ZSTD_isError(182 ZSTD_CCtx_setParameter(Cctx, ZSTD_c_compressionLevel, Level))) {183 ZSTD_freeCCtx(Cctx);184 report_bad_alloc_error("Failed to set ZSTD_c_compressionLevel");185 }186 187 unsigned long CompressedBufferSize = ZSTD_compressBound(Input.size());188 CompressedBuffer.resize_for_overwrite(CompressedBufferSize);189 190 size_t const CompressedSize =191 ZSTD_compress2(Cctx, CompressedBuffer.data(), CompressedBufferSize,192 Input.data(), Input.size());193 194 ZSTD_freeCCtx(Cctx);195 196 if (ZSTD_isError(CompressedSize))197 report_bad_alloc_error("Compression failed");198 199 __msan_unpoison(CompressedBuffer.data(), CompressedSize);200 if (CompressedSize < CompressedBuffer.size())201 CompressedBuffer.truncate(CompressedSize);202}203 204Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,205 size_t &UncompressedSize) {206 const size_t Res = ::ZSTD_decompress(207 Output, UncompressedSize, (const uint8_t *)Input.data(), Input.size());208 UncompressedSize = Res;209 if (ZSTD_isError(Res))210 return make_error<StringError>(ZSTD_getErrorName(Res),211 inconvertibleErrorCode());212 // Tell MemorySanitizer that zstd output buffer is fully initialized.213 // This avoids a false report when running LLVM with uninstrumented ZLib.214 __msan_unpoison(Output, UncompressedSize);215 return Error::success();216}217 218Error zstd::decompress(ArrayRef<uint8_t> Input,219 SmallVectorImpl<uint8_t> &Output,220 size_t UncompressedSize) {221 Output.resize_for_overwrite(UncompressedSize);222 Error E = zstd::decompress(Input, Output.data(), UncompressedSize);223 if (UncompressedSize < Output.size())224 Output.truncate(UncompressedSize);225 return E;226}227 228#else229bool zstd::isAvailable() { return false; }230void zstd::compress(ArrayRef<uint8_t> Input,231 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level,232 bool EnableLdm) {233 llvm_unreachable("zstd::compress is unavailable");234}235Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output,236 size_t &UncompressedSize) {237 llvm_unreachable("zstd::decompress is unavailable");238}239Error zstd::decompress(ArrayRef<uint8_t> Input,240 SmallVectorImpl<uint8_t> &Output,241 size_t UncompressedSize) {242 llvm_unreachable("zstd::decompress is unavailable");243}244#endif245