Skip to content

Commit

Permalink
[Support/Compression] - Change zlib API to return Error instead of cu…
Browse files Browse the repository at this point in the history
…stom status.

Previously API returned custom enum values.
Patch changes it to return Error with string description.
That should help users to report errors in universal way.

Differential revision: https://reviews.llvm.org/D28684

llvm-svn: 292214
  • Loading branch information
George Rimar committed Jan 17, 2017
1 parent e1ff0cf commit e29a32e
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 72 deletions.
24 changes: 8 additions & 16 deletions llvm/include/llvm/Support/Compression.h
Expand Up @@ -18,6 +18,7 @@

namespace llvm {
template <typename T> class SmallVectorImpl;
class Error;
class StringRef;

namespace zlib {
Expand All @@ -29,26 +30,17 @@ enum CompressionLevel {
BestSizeCompression
};

enum Status {
StatusOK,
StatusUnsupported, // zlib is unavailable
StatusOutOfMemory, // there was not enough memory
StatusBufferTooShort, // there was not enough room in the output buffer
StatusInvalidArg, // invalid input parameter
StatusInvalidData // data was corrupted or incomplete
};

bool isAvailable();

Status compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level = DefaultCompression);
Error compress(StringRef InputBuffer, SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level = DefaultCompression);

Status uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize);
Error uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize);

Status uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize);
Error uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize);

uint32_t crc32(StringRef Buffer);

Expand Down
9 changes: 5 additions & 4 deletions llvm/lib/MC/ELFObjectWriter.cpp
Expand Up @@ -32,6 +32,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/StringSaver.h"
#include <vector>
Expand Down Expand Up @@ -1037,10 +1038,10 @@ void ELFObjectWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec,
setStream(OldStream);

SmallVector<char, 128> CompressedContents;
zlib::Status Success = zlib::compress(
StringRef(UncompressedData.data(), UncompressedData.size()),
CompressedContents);
if (Success != zlib::StatusOK) {
if (Error E = zlib::compress(
StringRef(UncompressedData.data(), UncompressedData.size()),
CompressedContents)) {
consumeError(std::move(E));
getStream() << UncompressedData;
return;
}
Expand Down
5 changes: 1 addition & 4 deletions llvm/lib/Object/Decompressor.cpp
Expand Up @@ -95,8 +95,5 @@ Error Decompressor::decompress(SmallString<32> &Out) {

Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
size_t Size = Buffer.size();
zlib::Status Status = zlib::uncompress(SectionData, Buffer.data(), Size);
if (Status != zlib::StatusOK)
return createError("decompression failed");
return Error::success();
return zlib::uncompress(SectionData, Buffer.data(), Size);
}
17 changes: 10 additions & 7 deletions llvm/lib/ProfileData/InstrProf.cpp
Expand Up @@ -271,12 +271,12 @@ Error collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
}

SmallString<128> CompressedNameStrings;
zlib::Status Success =
zlib::compress(StringRef(UncompressedNameStrings), CompressedNameStrings,
zlib::BestSizeCompression);

if (Success != zlib::StatusOK)
Error E = zlib::compress(StringRef(UncompressedNameStrings),
CompressedNameStrings, zlib::BestSizeCompression);
if (E) {
consumeError(std::move(E));
return make_error<InstrProfError>(instrprof_error::compress_failed);
}

return WriteStringToResult(CompressedNameStrings.size(),
CompressedNameStrings);
Expand Down Expand Up @@ -315,9 +315,12 @@ Error readPGOFuncNameStrings(StringRef NameStrings, InstrProfSymtab &Symtab) {
if (isCompressed) {
StringRef CompressedNameStrings(reinterpret_cast<const char *>(P),
CompressedSize);
if (zlib::uncompress(CompressedNameStrings, UncompressedNameStrings,
UncompressedSize) != zlib::StatusOK)
if (Error E =
zlib::uncompress(CompressedNameStrings, UncompressedNameStrings,
UncompressedSize)) {
consumeError(std::move(E));
return make_error<InstrProfError>(instrprof_error::uncompress_failed);
}
P += CompressedSize;
NameStrings = StringRef(UncompressedNameStrings.data(),
UncompressedNameStrings.size());
Expand Down
83 changes: 47 additions & 36 deletions llvm/lib/Support/Compression.cpp
Expand Up @@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#if LLVM_ENABLE_ZLIB == 1 && HAVE_ZLIB_H
#include <zlib.h>
Expand All @@ -24,6 +25,10 @@
using namespace llvm;

#if LLVM_ENABLE_ZLIB == 1 && HAVE_LIBZ
static Error createError(StringRef Err) {
return make_error<StringError>(Err, inconvertibleErrorCode());
}

static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
switch (Level) {
case zlib::NoCompression: return 0;
Expand All @@ -34,53 +39,59 @@ static int encodeZlibCompressionLevel(zlib::CompressionLevel Level) {
llvm_unreachable("Invalid zlib::CompressionLevel!");
}

static zlib::Status encodeZlibReturnValue(int ReturnValue) {
switch (ReturnValue) {
case Z_OK: return zlib::StatusOK;
case Z_MEM_ERROR: return zlib::StatusOutOfMemory;
case Z_BUF_ERROR: return zlib::StatusBufferTooShort;
case Z_STREAM_ERROR: return zlib::StatusInvalidArg;
case Z_DATA_ERROR: return zlib::StatusInvalidData;
default: llvm_unreachable("unknown zlib return status!");
static StringRef convertZlibCodeToString(int Code) {
switch (Code) {
case Z_MEM_ERROR:
return "zlib error: Z_MEM_ERROR";
case Z_BUF_ERROR:
return "zlib error: Z_BUF_ERROR";
case Z_STREAM_ERROR:
return "zlib error: Z_STREAM_ERROR";
case Z_DATA_ERROR:
return "zlib error: Z_DATA_ERROR";
case Z_OK:
default:
llvm_unreachable("unknown or unexpected zlib status code");
}
}

bool zlib::isAvailable() { return true; }
zlib::Status zlib::compress(StringRef InputBuffer,
SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level) {

Error zlib::compress(StringRef InputBuffer,
SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level) {
unsigned long CompressedSize = ::compressBound(InputBuffer.size());
CompressedBuffer.resize(CompressedSize);
int CLevel = encodeZlibCompressionLevel(Level);
Status Res = encodeZlibReturnValue(::compress2(
(Bytef *)CompressedBuffer.data(), &CompressedSize,
(const Bytef *)InputBuffer.data(), InputBuffer.size(), CLevel));
int Res = ::compress2((Bytef *)CompressedBuffer.data(), &CompressedSize,
(const Bytef *)InputBuffer.data(), InputBuffer.size(),
CLevel);
// Tell MemorySanitizer that zlib output buffer is fully initialized.
// This avoids a false report when running LLVM with uninstrumented ZLib.
__msan_unpoison(CompressedBuffer.data(), CompressedSize);
CompressedBuffer.resize(CompressedSize);
return Res;
return Res ? createError(convertZlibCodeToString(Res)) : Error::success();
}

zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize) {
Status Res = encodeZlibReturnValue(
Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize) {
int Res =
::uncompress((Bytef *)UncompressedBuffer, (uLongf *)&UncompressedSize,
(const Bytef *)InputBuffer.data(), InputBuffer.size()));
(const Bytef *)InputBuffer.data(), InputBuffer.size());
// Tell MemorySanitizer that zlib output buffer is fully initialized.
// This avoids a false report when running LLVM with uninstrumented ZLib.
__msan_unpoison(UncompressedBuffer, UncompressedSize);
return Res;
return Res ? createError(convertZlibCodeToString(Res)) : Error::success();
}

zlib::Status zlib::uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize) {
Error zlib::uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize) {
UncompressedBuffer.resize(UncompressedSize);
Status Res =
Error E =
uncompress(InputBuffer, UncompressedBuffer.data(), UncompressedSize);
UncompressedBuffer.resize(UncompressedSize);
return Res;
return E;
}

uint32_t zlib::crc32(StringRef Buffer) {
Expand All @@ -89,19 +100,19 @@ uint32_t zlib::crc32(StringRef Buffer) {

#else
bool zlib::isAvailable() { return false; }
zlib::Status zlib::compress(StringRef InputBuffer,
SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level) {
return zlib::StatusUnsupported;
Error zlib::compress(StringRef InputBuffer,
SmallVectorImpl<char> &CompressedBuffer,
CompressionLevel Level) {
llvm_unreachable("zlib::compress is unavailable");
}
zlib::Status zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize) {
return zlib::StatusUnsupported;
Error zlib::uncompress(StringRef InputBuffer, char *UncompressedBuffer,
size_t &UncompressedSize) {
llvm_unreachable("zlib::uncompress is unavailable");
}
zlib::Status zlib::uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize) {
return zlib::StatusUnsupported;
Error zlib::uncompress(StringRef InputBuffer,
SmallVectorImpl<char> &UncompressedBuffer,
size_t UncompressedSize) {
llvm_unreachable("zlib::uncompress is unavailable");
}
uint32_t zlib::crc32(StringRef Buffer) {
llvm_unreachable("zlib::crc32 is unavailable");
Expand Down
17 changes: 12 additions & 5 deletions llvm/unittests/Support/CompressionTest.cpp
Expand Up @@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//

#include "llvm/Support/Compression.h"
#include "llvm/Support/Error.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/config.h"
Expand All @@ -26,15 +27,21 @@ namespace {
void TestZlibCompression(StringRef Input, zlib::CompressionLevel Level) {
SmallString<32> Compressed;
SmallString<32> Uncompressed;
EXPECT_EQ(zlib::StatusOK, zlib::compress(Input, Compressed, Level));

Error E = zlib::compress(Input, Compressed, Level);
EXPECT_FALSE(E);
consumeError(std::move(E));

// Check that uncompressed buffer is the same as original.
EXPECT_EQ(zlib::StatusOK,
zlib::uncompress(Compressed, Uncompressed, Input.size()));
E = zlib::uncompress(Compressed, Uncompressed, Input.size());
EXPECT_FALSE(E);
consumeError(std::move(E));

EXPECT_EQ(Input, Uncompressed);
if (Input.size() > 0) {
// Uncompression fails if expected length is too short.
EXPECT_EQ(zlib::StatusBufferTooShort,
zlib::uncompress(Compressed, Uncompressed, Input.size() - 1));
E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1);
EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E)));
}
}

Expand Down

0 comments on commit e29a32e

Please sign in to comment.