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 27 using namespace llvm; 28 using namespace llvm::compression; 29 30 const 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 46 void 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 58 Error 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 69 Error 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 81 Error 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 89 static 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 105 bool zlib::isAvailable() { return true; } 106 107 void 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 123 Error 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 135 Error 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 146 bool zlib::isAvailable() { return false; } 147 void zlib::compress(ArrayRef<uint8_t> Input, 148 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 149 llvm_unreachable("zlib::compress is unavailable"); 150 } 151 Error zlib::decompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 152 size_t &UncompressedSize) { 153 llvm_unreachable("zlib::decompress is unavailable"); 154 } 155 Error 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 164 bool zstd::isAvailable() { return true; } 165 166 #include <zstd.h> // Ensure ZSTD library is included 167 168 void 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 204 Error 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 // Tell MemorySanitizer that zstd output buffer is fully initialized. 210 // This avoids a false report when running LLVM with uninstrumented ZLib. 211 __msan_unpoison(Output, UncompressedSize); 212 return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res), 213 inconvertibleErrorCode()) 214 : Error::success(); 215 } 216 217 Error zstd::decompress(ArrayRef<uint8_t> Input, 218 SmallVectorImpl<uint8_t> &Output, 219 size_t UncompressedSize) { 220 Output.resize_for_overwrite(UncompressedSize); 221 Error E = zstd::decompress(Input, Output.data(), UncompressedSize); 222 if (UncompressedSize < Output.size()) 223 Output.truncate(UncompressedSize); 224 return E; 225 } 226 227 #else 228 bool zstd::isAvailable() { return false; } 229 void zstd::compress(ArrayRef<uint8_t> Input, 230 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level, 231 bool EnableLdm) { 232 llvm_unreachable("zstd::compress is unavailable"); 233 } 234 Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 235 size_t &UncompressedSize) { 236 llvm_unreachable("zstd::decompress is unavailable"); 237 } 238 Error zstd::decompress(ArrayRef<uint8_t> Input, 239 SmallVectorImpl<uint8_t> &Output, 240 size_t UncompressedSize) { 241 llvm_unreachable("zstd::decompress is unavailable"); 242 } 243 #endif 244