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(compression::Format F, ArrayRef<uint8_t> Input, 59 SmallVectorImpl<uint8_t> &Output, 60 size_t UncompressedSize) { 61 switch (F) { 62 case compression::Format::Zlib: 63 return zlib::uncompress(Input, Output, UncompressedSize); 64 case compression::Format::Zstd: 65 return zstd::uncompress(Input, Output, UncompressedSize); 66 } 67 llvm_unreachable(""); 68 } 69 70 Error compression::decompress(DebugCompressionType T, ArrayRef<uint8_t> Input, 71 SmallVectorImpl<uint8_t> &Output, 72 size_t UncompressedSize) { 73 return decompress(formatFor(T), Input, Output, UncompressedSize); 74 } 75 76 #if LLVM_ENABLE_ZLIB 77 78 static StringRef convertZlibCodeToString(int Code) { 79 switch (Code) { 80 case Z_MEM_ERROR: 81 return "zlib error: Z_MEM_ERROR"; 82 case Z_BUF_ERROR: 83 return "zlib error: Z_BUF_ERROR"; 84 case Z_STREAM_ERROR: 85 return "zlib error: Z_STREAM_ERROR"; 86 case Z_DATA_ERROR: 87 return "zlib error: Z_DATA_ERROR"; 88 case Z_OK: 89 default: 90 llvm_unreachable("unknown or unexpected zlib status code"); 91 } 92 } 93 94 bool zlib::isAvailable() { return true; } 95 96 void zlib::compress(ArrayRef<uint8_t> Input, 97 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 98 unsigned long CompressedSize = ::compressBound(Input.size()); 99 CompressedBuffer.resize_for_overwrite(CompressedSize); 100 int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize, 101 (const Bytef *)Input.data(), Input.size(), Level); 102 if (Res == Z_MEM_ERROR) 103 report_bad_alloc_error("Allocation failed"); 104 assert(Res == Z_OK); 105 // Tell MemorySanitizer that zlib output buffer is fully initialized. 106 // This avoids a false report when running LLVM with uninstrumented ZLib. 107 __msan_unpoison(CompressedBuffer.data(), CompressedSize); 108 if (CompressedSize < CompressedBuffer.size()) 109 CompressedBuffer.truncate(CompressedSize); 110 } 111 112 Error zlib::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 113 size_t &UncompressedSize) { 114 int Res = 115 ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize, 116 (const Bytef *)Input.data(), Input.size()); 117 // Tell MemorySanitizer that zlib output buffer is fully initialized. 118 // This avoids a false report when running LLVM with uninstrumented ZLib. 119 __msan_unpoison(UncompressedBuffer, UncompressedSize); 120 return Res ? make_error<StringError>(convertZlibCodeToString(Res), 121 inconvertibleErrorCode()) 122 : Error::success(); 123 } 124 125 Error zlib::uncompress(ArrayRef<uint8_t> Input, 126 SmallVectorImpl<uint8_t> &UncompressedBuffer, 127 size_t UncompressedSize) { 128 UncompressedBuffer.resize_for_overwrite(UncompressedSize); 129 Error E = 130 zlib::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); 131 if (UncompressedSize < UncompressedBuffer.size()) 132 UncompressedBuffer.truncate(UncompressedSize); 133 return E; 134 } 135 136 #else 137 bool zlib::isAvailable() { return false; } 138 void zlib::compress(ArrayRef<uint8_t> Input, 139 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 140 llvm_unreachable("zlib::compress is unavailable"); 141 } 142 Error zlib::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 143 size_t &UncompressedSize) { 144 llvm_unreachable("zlib::uncompress is unavailable"); 145 } 146 Error zlib::uncompress(ArrayRef<uint8_t> Input, 147 SmallVectorImpl<uint8_t> &UncompressedBuffer, 148 size_t UncompressedSize) { 149 llvm_unreachable("zlib::uncompress is unavailable"); 150 } 151 #endif 152 153 #if LLVM_ENABLE_ZSTD 154 155 bool zstd::isAvailable() { return true; } 156 157 void zstd::compress(ArrayRef<uint8_t> Input, 158 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 159 unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size()); 160 CompressedBuffer.resize_for_overwrite(CompressedBufferSize); 161 unsigned long CompressedSize = 162 ::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize, 163 (const char *)Input.data(), Input.size(), Level); 164 if (ZSTD_isError(CompressedSize)) 165 report_bad_alloc_error("Allocation failed"); 166 // Tell MemorySanitizer that zstd output buffer is fully initialized. 167 // This avoids a false report when running LLVM with uninstrumented ZLib. 168 __msan_unpoison(CompressedBuffer.data(), CompressedSize); 169 if (CompressedSize < CompressedBuffer.size()) 170 CompressedBuffer.truncate(CompressedSize); 171 } 172 173 Error zstd::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 174 size_t &UncompressedSize) { 175 const size_t Res = 176 ::ZSTD_decompress(UncompressedBuffer, UncompressedSize, 177 (const uint8_t *)Input.data(), Input.size()); 178 UncompressedSize = Res; 179 // Tell MemorySanitizer that zstd output buffer is fully initialized. 180 // This avoids a false report when running LLVM with uninstrumented ZLib. 181 __msan_unpoison(UncompressedBuffer, UncompressedSize); 182 return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res), 183 inconvertibleErrorCode()) 184 : Error::success(); 185 } 186 187 Error zstd::uncompress(ArrayRef<uint8_t> Input, 188 SmallVectorImpl<uint8_t> &UncompressedBuffer, 189 size_t UncompressedSize) { 190 UncompressedBuffer.resize_for_overwrite(UncompressedSize); 191 Error E = 192 zstd::uncompress(Input, UncompressedBuffer.data(), UncompressedSize); 193 if (UncompressedSize < UncompressedBuffer.size()) 194 UncompressedBuffer.truncate(UncompressedSize); 195 return E; 196 } 197 198 #else 199 bool zstd::isAvailable() { return false; } 200 void zstd::compress(ArrayRef<uint8_t> Input, 201 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) { 202 llvm_unreachable("zstd::compress is unavailable"); 203 } 204 Error zstd::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer, 205 size_t &UncompressedSize) { 206 llvm_unreachable("zstd::uncompress is unavailable"); 207 } 208 Error zstd::uncompress(ArrayRef<uint8_t> Input, 209 SmallVectorImpl<uint8_t> &UncompressedBuffer, 210 size_t UncompressedSize) { 211 llvm_unreachable("zstd::uncompress is unavailable"); 212 } 213 #endif 214