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); 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 void 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 182 Error 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 195 Error 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 206 bool zstd::isAvailable() { return false; } 207 void zstd::compress(ArrayRef<uint8_t> Input, 208 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 209 llvm_unreachable("zstd::compress is unavailable"); 210 } 211 Error zstd::decompress(ArrayRef<uint8_t> Input, uint8_t *Output, 212 size_t &UncompressedSize) { 213 llvm_unreachable("zstd::decompress is unavailable"); 214 } 215 Error 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