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-exception 6// 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_ZLIB 21#include <zlib.h> 22#endif 23#if LLVM_ENABLE_ZSTD 24#include <zstd.h> 25#endif 26 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); 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_ZLIB 88 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#else 146bool 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#endif 161 162#if LLVM_ENABLE_ZSTD 163 164bool zstd::isAvailable() { return true; } 165 166void zstd::compress(ArrayRef<uint8_t> Input, 167 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 168 unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); 169 CompressedBuffer.resize_for_overwrite(CompressedBufferSize); 170 unsigned long CompressedSize = 171 ::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize, 172 (const char *)Input.data(), Input.size(), Level); 173 if (ZSTD_isError(CompressedSize)) 174 report_bad_alloc_error("Allocation failed"); 175 // Tell MemorySanitizer that zstd output buffer is fully initialized. 176 // This avoids a false report when running LLVM with uninstrumented ZLib. 177 __msan_unpoison(CompressedBuffer.data(), CompressedSize); 178 if (CompressedSize < CompressedBuffer.size()) 179 CompressedBuffer.truncate(CompressedSize); 180} 181 182Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 183 size_t &UncompressedSize) { 184 const size_t Res = ::ZSTD_decompress( 185 Output, UncompressedSize, (const uint8_t *)Input.data(), Input.size()); 186 UncompressedSize = Res; 187 // Tell MemorySanitizer that zstd output buffer is fully initialized. 188 // This avoids a false report when running LLVM with uninstrumented ZLib. 189 __msan_unpoison(Output, UncompressedSize); 190 return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res), 191 inconvertibleErrorCode()) 192 : Error::success(); 193} 194 195Error zstd::decompress(ArrayRef<uint8_t> Input, 196 SmallVectorImpl<uint8_t> &Output, 197 size_t UncompressedSize) { 198 Output.resize_for_overwrite(UncompressedSize); 199 Error E = zstd::decompress(Input, Output.data(), UncompressedSize); 200 if (UncompressedSize < Output.size()) 201 Output.truncate(UncompressedSize); 202 return E; 203} 204 205#else 206bool zstd::isAvailable() { return false; } 207void zstd::compress(ArrayRef<uint8_t> Input, 208 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 209 llvm_unreachable("zstd::compress is unavailable"); 210} 211Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 212 size_t &UncompressedSize) { 213 llvm_unreachable("zstd::decompress is unavailable"); 214} 215Error zstd::decompress(ArrayRef<uint8_t> Input, 216 SmallVectorImpl<uint8_t> &Output, 217 size_t UncompressedSize) { 218 llvm_unreachable("zstd::decompress is unavailable"); 219} 220#endif 221