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 #if LLVM_ENABLE_ZLIB
31
convertZlibCodeToString(int Code)32 static StringRef convertZlibCodeToString(int Code) {
33 switch (Code) {
34 case Z_MEM_ERROR:
35 return "zlib error: Z_MEM_ERROR";
36 case Z_BUF_ERROR:
37 return "zlib error: Z_BUF_ERROR";
38 case Z_STREAM_ERROR:
39 return "zlib error: Z_STREAM_ERROR";
40 case Z_DATA_ERROR:
41 return "zlib error: Z_DATA_ERROR";
42 case Z_OK:
43 default:
44 llvm_unreachable("unknown or unexpected zlib status code");
45 }
46 }
47
isAvailable()48 bool zlib::isAvailable() { return true; }
49
compress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & CompressedBuffer,int Level)50 void zlib::compress(ArrayRef<uint8_t> Input,
51 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
52 unsigned long CompressedSize = ::compressBound(Input.size());
53 CompressedBuffer.resize_for_overwrite(CompressedSize);
54 int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,
55 (const Bytef *)Input.data(), Input.size(), Level);
56 if (Res == Z_MEM_ERROR)
57 report_bad_alloc_error("Allocation failed");
58 assert(Res == Z_OK);
59 // Tell MemorySanitizer that zlib output buffer is fully initialized.
60 // This avoids a false report when running LLVM with uninstrumented ZLib.
61 __msan_unpoison(CompressedBuffer.data(), CompressedSize);
62 if (CompressedSize < CompressedBuffer.size())
63 CompressedBuffer.truncate(CompressedSize);
64 }
65
uncompress(ArrayRef<uint8_t> Input,uint8_t * UncompressedBuffer,size_t & UncompressedSize)66 Error zlib::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
67 size_t &UncompressedSize) {
68 int Res =
69 ::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize,
70 (const Bytef *)Input.data(), Input.size());
71 // Tell MemorySanitizer that zlib output buffer is fully initialized.
72 // This avoids a false report when running LLVM with uninstrumented ZLib.
73 __msan_unpoison(UncompressedBuffer, UncompressedSize);
74 return Res ? make_error<StringError>(convertZlibCodeToString(Res),
75 inconvertibleErrorCode())
76 : Error::success();
77 }
78
uncompress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & UncompressedBuffer,size_t UncompressedSize)79 Error zlib::uncompress(ArrayRef<uint8_t> Input,
80 SmallVectorImpl<uint8_t> &UncompressedBuffer,
81 size_t UncompressedSize) {
82 UncompressedBuffer.resize_for_overwrite(UncompressedSize);
83 Error E =
84 zlib::uncompress(Input, UncompressedBuffer.data(), UncompressedSize);
85 if (UncompressedSize < UncompressedBuffer.size())
86 UncompressedBuffer.truncate(UncompressedSize);
87 return E;
88 }
89
90 #else
isAvailable()91 bool zlib::isAvailable() { return false; }
compress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & CompressedBuffer,int Level)92 void zlib::compress(ArrayRef<uint8_t> Input,
93 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
94 llvm_unreachable("zlib::compress is unavailable");
95 }
uncompress(ArrayRef<uint8_t> Input,uint8_t * UncompressedBuffer,size_t & UncompressedSize)96 Error zlib::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
97 size_t &UncompressedSize) {
98 llvm_unreachable("zlib::uncompress is unavailable");
99 }
uncompress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & UncompressedBuffer,size_t UncompressedSize)100 Error zlib::uncompress(ArrayRef<uint8_t> Input,
101 SmallVectorImpl<uint8_t> &UncompressedBuffer,
102 size_t UncompressedSize) {
103 llvm_unreachable("zlib::uncompress is unavailable");
104 }
105 #endif
106
107 #if LLVM_ENABLE_ZSTD
108
isAvailable()109 bool zstd::isAvailable() { return true; }
110
compress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & CompressedBuffer,int Level)111 void zstd::compress(ArrayRef<uint8_t> Input,
112 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
113 unsigned long CompressedBufferSize = ::ZSTD_compressBound(Input.size());
114 CompressedBuffer.resize_for_overwrite(CompressedBufferSize);
115 unsigned long CompressedSize =
116 ::ZSTD_compress((char *)CompressedBuffer.data(), CompressedBufferSize,
117 (const char *)Input.data(), Input.size(), Level);
118 if (ZSTD_isError(CompressedSize))
119 report_bad_alloc_error("Allocation failed");
120 // Tell MemorySanitizer that zstd output buffer is fully initialized.
121 // This avoids a false report when running LLVM with uninstrumented ZLib.
122 __msan_unpoison(CompressedBuffer.data(), CompressedSize);
123 if (CompressedSize < CompressedBuffer.size())
124 CompressedBuffer.truncate(CompressedSize);
125 }
126
uncompress(ArrayRef<uint8_t> Input,uint8_t * UncompressedBuffer,size_t & UncompressedSize)127 Error zstd::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
128 size_t &UncompressedSize) {
129 const size_t Res =
130 ::ZSTD_decompress(UncompressedBuffer, UncompressedSize,
131 (const uint8_t *)Input.data(), Input.size());
132 UncompressedSize = Res;
133 // Tell MemorySanitizer that zstd output buffer is fully initialized.
134 // This avoids a false report when running LLVM with uninstrumented ZLib.
135 __msan_unpoison(UncompressedBuffer, UncompressedSize);
136 return ZSTD_isError(Res) ? make_error<StringError>(ZSTD_getErrorName(Res),
137 inconvertibleErrorCode())
138 : Error::success();
139 }
140
uncompress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & UncompressedBuffer,size_t UncompressedSize)141 Error zstd::uncompress(ArrayRef<uint8_t> Input,
142 SmallVectorImpl<uint8_t> &UncompressedBuffer,
143 size_t UncompressedSize) {
144 UncompressedBuffer.resize_for_overwrite(UncompressedSize);
145 Error E =
146 zstd::uncompress(Input, UncompressedBuffer.data(), UncompressedSize);
147 if (UncompressedSize < UncompressedBuffer.size())
148 UncompressedBuffer.truncate(UncompressedSize);
149 return E;
150 }
151
152 #else
isAvailable()153 bool zstd::isAvailable() { return false; }
compress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & CompressedBuffer,int Level)154 void zstd::compress(ArrayRef<uint8_t> Input,
155 SmallVectorImpl<uint8_t> &CompressedBuffer, int Level) {
156 llvm_unreachable("zstd::compress is unavailable");
157 }
uncompress(ArrayRef<uint8_t> Input,uint8_t * UncompressedBuffer,size_t & UncompressedSize)158 Error zstd::uncompress(ArrayRef<uint8_t> Input, uint8_t *UncompressedBuffer,
159 size_t &UncompressedSize) {
160 llvm_unreachable("zstd::uncompress is unavailable");
161 }
uncompress(ArrayRef<uint8_t> Input,SmallVectorImpl<uint8_t> & UncompressedBuffer,size_t UncompressedSize)162 Error zstd::uncompress(ArrayRef<uint8_t> Input,
163 SmallVectorImpl<uint8_t> &UncompressedBuffer,
164 size_t UncompressedSize) {
165 llvm_unreachable("zstd::uncompress is unavailable");
166 }
167 #endif
168