Bug 1340901 - Update Snappy to version 1.1.8. r=dom-workers-and-storage-reviewers,asuth

Add a static assertion in IndexedDB to detect future updates.

Differential Revision: https://phabricator.services.mozilla.com/D56708
This commit is contained in:
ssengupta 2021-01-26 17:27:14 +00:00
Родитель 9b4822e0ff
Коммит 070a49e060
18 изменённых файлов: 1280 добавлений и 3306 удалений

Просмотреть файл

@ -61,6 +61,8 @@ class nsIFile;
namespace mozilla::dom::indexedDB {
static_assert(SNAPPY_VERSION == 0x010108);
using mozilla::ipc::IsOnBackgroundThread;
namespace {

Просмотреть файл

@ -4,23 +4,21 @@ Mozilla does not modify the actual snappy source with the exception of the
'snappy-stubs-public.h' header. We have replaced its build system with our own.
Snappy comes from:
http://code.google.com/p/snappy/
https://github.com/google/snappy
We are currently using revision: 114
We are currently using revision: 1.1.8
To upgrade to a newer version:
1. Check out the new code using subversion.
2. Update 'snappy-stubs-public.h' in this directory with any changes that were
made to 'snappy-stubs-public.h.in' in the new source.
3. Copy the major/minor/patch versions from 'configure.ac' into
3. Copy the major/minor/patch versions from 'CMakeLists.txt' into
'snappy-stubs-public.h'.
4. Copy all source files from the new version into the src subdirectory. The
following files are not needed:
- 'autom4te.cache' subdirectory
- 'm4' subdirectory
following are not needed:
- 'CMakeLists.txt' file
- 'cmake' subdirectory
- 'docs' subdirectory
- 'testdata' subdirectory
- 'autogen.sh'
- 'configure.ac'
- 'Makefile.am'
- 'snappy.pc.in'
5. Update the revision stamp in this file.

Просмотреть файл

@ -39,14 +39,14 @@
#include <stdint.h>
#if defined IS_BIG_ENDIAN || defined __BIG_ENDIAN__
#define WORDS_BIGENDIAN
# define WORDS_BIGENDIAN
#endif
#define SNAPPY_MAJOR 1
#define SNAPPY_MINOR 1
#define SNAPPY_PATCHLEVEL 3
#define SNAPPY_PATCHLEVEL 8
#define SNAPPY_VERSION \
((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
#include <string>
@ -64,22 +64,22 @@ typedef uint64_t uint64;
typedef std::string string;
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
# define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
struct iovec {
void* iov_base;
size_t iov_len;
void* iov_base;
size_t iov_len;
};
#if defined(_WIN32) || defined(_WIN64)
#if defined(_WIN64)
# if defined(_WIN64)
typedef __int64 LONG_PTR;
#else
# else
typedef long LONG_PTR;
#endif
# endif
typedef LONG_PTR SSIZE_T;
typedef SSIZE_T ssize_t;
#endif

Просмотреть файл

@ -0,0 +1,26 @@
# How to Contribute
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement
Contributions to this project must be accompanied by a Contributor License
Agreement. You (or your employer) retain the copyright to your contribution,
this simply gives us permission to use and redistribute your contributions as
part of the project. Head over to <https://cla.developers.google.com/> to see
your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one
(even if it was for a different project), you probably don't need to do it
again.
## Code reviews
All submissions, including submissions by project members, require review. We
use GitHub pull requests for this purpose. Consult
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
information on using pull requests.
Please make sure that all the automated checks (CLA, AppVeyor, Travis) pass for
your pull requests. Pull requests whose checks fail may be ignored.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,3 +1,51 @@
Snappy v1.1.8, January 15th 2020:
* Small performance improvements.
* Removed snappy::string alias for std::string.
* Improved CMake configuration.
Snappy v1.1.7, August 24th 2017:
* Improved CMake build support for 64-bit Linux distributions.
* MSVC builds now use MSVC-specific intrinsics that map to clzll.
* ARM64 (AArch64) builds use the code paths optimized for 64-bit processors.
Snappy v1.1.6, July 12th 2017:
This is a re-release of v1.1.5 with proper SONAME / SOVERSION values.
Snappy v1.1.5, June 28th 2017:
This release has broken SONAME / SOVERSION values. Users of snappy as a shared
library should avoid 1.1.5 and use 1.1.6 instead. SONAME / SOVERSION errors will
manifest as the dynamic library loader complaining that it cannot find snappy's
shared library file (libsnappy.so / libsnappy.dylib), or that the library it
found does not have the required version. 1.1.6 has the same code as 1.1.5, but
carries build configuration fixes for the issues above.
* Add CMake build support. The autoconf build support is now deprecated, and
will be removed in the next release.
* Add AppVeyor configuration, for Windows CI coverage.
* Small performance improvement on little-endian PowerPC.
* Small performance improvement on LLVM with position-independent executables.
* Fix a few issues with various build environments.
Snappy v1.1.4, January 25th 2017:
* Fix a 1% performance regression when snappy is used in PIE executables.
* Improve compression performance by 5%.
* Improve decompression performance by 20%.
Snappy v1.1.3, July 6th 2015:
This is the first release to be done from GitHub, which means that

Просмотреть файл

@ -34,7 +34,7 @@ Snappy is intended to be fast. On a single core of a Core i7 processor
in 64-bit mode, it compresses at about 250 MB/sec or more and decompresses at
about 500 MB/sec or more. (These numbers are for the slowest inputs in our
benchmark suite; others are much faster.) In our tests, Snappy usually
is faster than algorithms in the same class (e.g. LZO, LZF, FastLZ, QuickLZ,
is faster than algorithms in the same class (e.g. LZO, LZF, QuickLZ,
etc.) while achieving comparable compression ratios.
Typical compression ratios (based on the benchmark suite) are about 1.5-1.7x
@ -51,8 +51,8 @@ In particular:
- Snappy uses 64-bit operations in several places to process more data at
once than would otherwise be possible.
- Snappy assumes unaligned 32- and 64-bit loads and stores are cheap.
On some platforms, these must be emulated with single-byte loads
- Snappy assumes unaligned 32 and 64-bit loads and stores are cheap.
On some platforms, these must be emulated with single-byte loads
and stores, which is much slower.
- Snappy assumes little-endian throughout, and needs to byte-swap data in
several places if running on a big-endian platform.
@ -62,25 +62,40 @@ Performance optimizations, whether for 64-bit x86 or other platforms,
are of course most welcome; see "Contact", below.
Building
========
You need the CMake version specified in [CMakeLists.txt](./CMakeLists.txt)
or later to build:
```bash
mkdir build
cd build && cmake ../ && make
```
Usage
=====
Note that Snappy, both the implementation and the main interface,
is written in C++. However, several third-party bindings to other languages
are available; see the home page at http://google.github.io/snappy/
for more information. Also, if you want to use Snappy from C code, you can
use the included C bindings in snappy-c.h.
are available; see the [home page](docs/README.md) for more information.
Also, if you want to use Snappy from C code, you can use the included C
bindings in snappy-c.h.
To use Snappy from your own C++ program, include the file "snappy.h" from
your calling file, and link against the compiled library.
There are many ways to call Snappy, but the simplest possible is
snappy::Compress(input.data(), input.size(), &output);
```c++
snappy::Compress(input.data(), input.size(), &output);
```
and similarly
snappy::Uncompress(input.data(), input.size(), &output);
```c++
snappy::Uncompress(input.data(), input.size(), &output);
```
where "input" and "output" are both instances of std::string.
@ -102,12 +117,12 @@ tests to verify you have not broken anything. Note that if you have the
Google Test library installed, unit test behavior (especially failures) will be
significantly more user-friendly. You can find Google Test at
http://github.com/google/googletest
https://github.com/google/googletest
You probably also want the gflags library for handling of command-line flags;
you can find it at
http://gflags.github.io/gflags/
https://gflags.github.io/gflags/
In addition to the unit tests, snappy contains microbenchmarks used to
tune compression and decompression performance. These are automatically run
@ -116,7 +131,7 @@ before the unit tests, but you can disable them using the flag
need to edit the source).
Finally, snappy can benchmark Snappy against a few other compression libraries
(zlib, LZO, LZF, FastLZ and QuickLZ), if they were detected at configure time.
(zlib, LZO, LZF, and QuickLZ), if they were detected at configure time.
To benchmark using a given file, give the compression algorithm you want to test
Snappy against (e.g. --zlib) and then a list of one or more file names on the
command line. The testdata/ directory contains the files used by the
@ -130,10 +145,4 @@ Contact
=======
Snappy is distributed through GitHub. For the latest version, a bug tracker,
and other information, see
http://google.github.io/snappy/
or the repository at
https://github.com/google/snappy
and other information, see https://github.com/google/snappy.

Просмотреть файл

@ -36,21 +36,30 @@
namespace snappy {
namespace internal {
// Working memory performs a single allocation to hold all scratch space
// required for compression.
class WorkingMemory {
public:
WorkingMemory() : large_table_(NULL) { }
~WorkingMemory() { delete[] large_table_; }
explicit WorkingMemory(size_t input_size);
~WorkingMemory();
// Allocates and clears a hash table using memory in "*this",
// stores the number of buckets in "*table_size" and returns a pointer to
// the base of the hash table.
uint16* GetHashTable(size_t input_size, int* table_size);
uint16* GetHashTable(size_t fragment_size, int* table_size) const;
char* GetScratchInput() const { return input_; }
char* GetScratchOutput() const { return output_; }
private:
uint16 small_table_[1<<10]; // 2KB
uint16* large_table_; // Allocated only when needed
char* mem_; // the allocated memory, never nullptr
size_t size_; // the size of the allocated memory, never 0
uint16* table_; // the pointer to the hashtable
char* input_; // the pointer to the input scratch buffer
char* output_; // the pointer to the output scratch buffer
DISALLOW_COPY_AND_ASSIGN(WorkingMemory);
// No copying
WorkingMemory(const WorkingMemory&);
void operator=(const WorkingMemory&);
};
// Flat array compression that does not emit the "uncompressed length"
@ -70,57 +79,72 @@ char* CompressFragment(const char* input,
uint16* table,
const int table_size);
// Return the largest n such that
// Find the largest n such that
//
// s1[0,n-1] == s2[0,n-1]
// and n <= (s2_limit - s2).
//
// Return make_pair(n, n < 8).
// Does not read *s2_limit or beyond.
// Does not read *(s1 + (s2_limit - s2)) or beyond.
// Requires that s2_limit >= s2.
//
// Separate implementation for x86_64, for speed. Uses the fact that
// x86_64 is little endian.
#if defined(ARCH_K8)
static inline int FindMatchLength(const char* s1,
const char* s2,
const char* s2_limit) {
// Separate implementation for 64-bit, little-endian cpus.
#if !defined(SNAPPY_IS_BIG_ENDIAN) && \
(defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM))
static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
const char* s2,
const char* s2_limit) {
assert(s2_limit >= s2);
int matched = 0;
size_t matched = 0;
// This block isn't necessary for correctness; we could just start looping
// immediately. As an optimization though, it is useful. It creates some not
// uncommon code paths that determine, without extra effort, whether the match
// length is less than 8. In short, we are hoping to avoid a conditional
// branch, and perhaps get better code layout from the C++ compiler.
if (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 8)) {
uint64 a1 = UNALIGNED_LOAD64(s1);
uint64 a2 = UNALIGNED_LOAD64(s2);
if (a1 != a2) {
return std::pair<size_t, bool>(Bits::FindLSBSetNonZero64(a1 ^ a2) >> 3,
true);
} else {
matched = 8;
s2 += 8;
}
}
// Find out how long the match is. We loop over the data 64 bits at a
// time until we find a 64-bit block that doesn't match; then we find
// the first non-matching bit and use that to calculate the total
// length of the match.
while (PREDICT_TRUE(s2 <= s2_limit - 8)) {
while (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 8)) {
if (UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched)) {
s2 += 8;
matched += 8;
} else {
// On current (mid-2008) Opteron models there is a 3% more
// efficient code sequence to find the first non-matching byte.
// However, what follows is ~10% better on Intel Core 2 and newer,
// and we expect AMD's bsf instruction to improve.
uint64 x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched);
int matching_bits = Bits::FindLSBSetNonZero64(x);
matched += matching_bits >> 3;
return matched;
assert(matched >= 8);
return std::pair<size_t, bool>(matched, false);
}
}
while (PREDICT_TRUE(s2 < s2_limit)) {
while (SNAPPY_PREDICT_TRUE(s2 < s2_limit)) {
if (s1[matched] == *s2) {
++s2;
++matched;
} else {
return matched;
return std::pair<size_t, bool>(matched, matched < 8);
}
}
return matched;
return std::pair<size_t, bool>(matched, matched < 8);
}
#else
static inline int FindMatchLength(const char* s1,
const char* s2,
const char* s2_limit) {
static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
const char* s2,
const char* s2_limit) {
// Implementation based on the x86-64 version, above.
assert(s2_limit >= s2);
int matched = 0;
@ -140,7 +164,7 @@ static inline int FindMatchLength(const char* s1,
++matched;
}
}
return matched;
return std::pair<size_t, bool>(matched, matched < 8);
}
#endif
@ -155,11 +179,6 @@ enum {
};
static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset.
// Mapping from i in range [0,4] to a mask to extract the bottom 8*i bits
static const uint32 wordmask[] = {
0u, 0xffu, 0xffffu, 0xffffffu, 0xffffffffu
};
// Data stored per entry in lookup table:
// Range Bits-used Description
// ------------------------------------

Просмотреть файл

@ -33,7 +33,7 @@
namespace snappy {
void Varint::Append32(string* s, uint32 value) {
void Varint::Append32(std::string* s, uint32 value) {
char buf[Varint::kMax32];
const char* p = Varint::Encode32(buf, value);
s->append(buf, p - buf);

Просмотреть файл

@ -45,6 +45,26 @@
#include <sys/mman.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if defined(_MSC_VER)
#include <intrin.h>
#endif // defined(_MSC_VER)
#ifndef __has_feature
#define __has_feature(x) 0
#endif
#if __has_feature(memory_sanitizer)
#include <sanitizer/msan_interface.h>
#define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
__msan_unpoison((address), (size))
#else
#define SNAPPY_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) /* empty */
#endif // __has_feature(memory_sanitizer)
#include "snappy-stubs-public.h"
#if defined(__x86_64__)
@ -52,6 +72,14 @@
// Enable 64-bit optimized versions of some routines.
#define ARCH_K8 1
#elif defined(__ppc64__)
#define ARCH_PPC 1
#elif defined(__aarch64__)
#define ARCH_ARM 1
#endif
// Needed by OS X, among others.
@ -59,10 +87,6 @@
#define MAP_ANONYMOUS MAP_ANON
#endif
// Pull in std::min, std::ostream, and the likes. This is safe because this
// header file is never used from any public header files.
using namespace std;
// The size of an array, if known at compile-time.
// Will give unexpected results if used on a pointer.
// We undefine it first, since some compilers already have a definition.
@ -73,11 +97,11 @@ using namespace std;
// Static prediction hints.
#ifdef HAVE_BUILTIN_EXPECT
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#define SNAPPY_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define SNAPPY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define PREDICT_FALSE(x) x
#define PREDICT_TRUE(x) x
#define SNAPPY_PREDICT_FALSE(x) x
#define SNAPPY_PREDICT_TRUE(x) x
#endif
// This is only used for recomputing the tag byte table used during
@ -96,9 +120,10 @@ static const int64 kint64max = static_cast<int64>(0x7FFFFFFFFFFFFFFFLL);
// Potentially unaligned loads and stores.
// x86 and PowerPC can simply do these loads and stores native.
// x86, PowerPC, and ARM64 can simply do these loads and stores native.
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) || \
defined(__aarch64__)
#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
@ -174,7 +199,7 @@ struct Unaligned32Struct {
((reinterpret_cast< ::snappy::base::internal::Unaligned32Struct *>(_p))->value = \
(_val))
// TODO(user): NEON supports unaligned 64-bit loads and stores.
// TODO: NEON supports unaligned 64-bit loads and stores.
// See if that would be more efficient on platforms supporting it,
// at least for copies.
@ -225,22 +250,8 @@ inline void UNALIGNED_STORE64(void *p, uint64 v) {
#endif
// This can be more efficient than UNALIGNED_LOAD64 + UNALIGNED_STORE64
// on some platforms, in particular ARM.
inline void UnalignedCopy64(const void *src, void *dst) {
if (sizeof(void *) == 8) {
UNALIGNED_STORE64(dst, UNALIGNED_LOAD64(src));
} else {
const char *src_char = reinterpret_cast<const char *>(src);
char *dst_char = reinterpret_cast<char *>(dst);
UNALIGNED_STORE32(dst_char, UNALIGNED_LOAD32(src_char));
UNALIGNED_STORE32(dst_char + 4, UNALIGNED_LOAD32(src_char + 4));
}
}
// The following guarantees declaration of the byte swap functions.
#ifdef WORDS_BIGENDIAN
#if defined(SNAPPY_IS_BIG_ENDIAN)
#ifdef HAVE_SYS_BYTEORDER_H
#include <sys/byteorder.h>
@ -297,7 +308,7 @@ inline uint64 bswap_64(uint64 x) {
#endif
#endif // WORDS_BIGENDIAN
#endif // defined(SNAPPY_IS_BIG_ENDIAN)
// Convert to little-endian storage, opposite of network format.
// Convert x from host to little endian: x = LittleEndian.FromHost(x);
@ -311,7 +322,7 @@ inline uint64 bswap_64(uint64 x) {
class LittleEndian {
public:
// Conversion functions.
#ifdef WORDS_BIGENDIAN
#if defined(SNAPPY_IS_BIG_ENDIAN)
static uint16 FromHost16(uint16 x) { return bswap_16(x); }
static uint16 ToHost16(uint16 x) { return bswap_16(x); }
@ -321,7 +332,7 @@ class LittleEndian {
static bool IsLittleEndian() { return false; }
#else // !defined(WORDS_BIGENDIAN)
#else // !defined(SNAPPY_IS_BIG_ENDIAN)
static uint16 FromHost16(uint16 x) { return x; }
static uint16 ToHost16(uint16 x) { return x; }
@ -331,7 +342,7 @@ class LittleEndian {
static bool IsLittleEndian() { return true; }
#endif // !defined(WORDS_BIGENDIAN)
#endif // !defined(SNAPPY_IS_BIG_ENDIAN)
// Functions to do unaligned loads and stores in little-endian order.
static uint16 Load16(const void *p) {
@ -354,6 +365,9 @@ class LittleEndian {
// Some bit-manipulation functions.
class Bits {
public:
// Return floor(log2(n)) for positive integer n.
static int Log2FloorNonZero(uint32 n);
// Return floor(log2(n)) for positive integer n. Returns -1 iff n == 0.
static int Log2Floor(uint32 n);
@ -361,31 +375,85 @@ class Bits {
// undefined value if n == 0. FindLSBSetNonZero() is similar to ffs() except
// that it's 0-indexed.
static int FindLSBSetNonZero(uint32 n);
#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
static int FindLSBSetNonZero64(uint64 n);
#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
private:
DISALLOW_COPY_AND_ASSIGN(Bits);
// No copying
Bits(const Bits&);
void operator=(const Bits&);
};
#ifdef HAVE_BUILTIN_CTZ
inline int Bits::Log2FloorNonZero(uint32 n) {
assert(n != 0);
// (31 ^ x) is equivalent to (31 - x) for x in [0, 31]. An easy proof
// represents subtraction in base 2 and observes that there's no carry.
//
// GCC and Clang represent __builtin_clz on x86 as 31 ^ _bit_scan_reverse(x).
// Using "31 ^" here instead of "31 -" allows the optimizer to strip the
// function body down to _bit_scan_reverse(x).
return 31 ^ __builtin_clz(n);
}
inline int Bits::Log2Floor(uint32 n) {
return n == 0 ? -1 : 31 ^ __builtin_clz(n);
return (n == 0) ? -1 : Bits::Log2FloorNonZero(n);
}
inline int Bits::FindLSBSetNonZero(uint32 n) {
assert(n != 0);
return __builtin_ctz(n);
}
#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
inline int Bits::FindLSBSetNonZero64(uint64 n) {
assert(n != 0);
return __builtin_ctzll(n);
}
#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
#elif defined(_MSC_VER)
inline int Bits::Log2FloorNonZero(uint32 n) {
assert(n != 0);
unsigned long where;
_BitScanReverse(&where, n);
return static_cast<int>(where);
}
inline int Bits::Log2Floor(uint32 n) {
unsigned long where;
if (_BitScanReverse(&where, n))
return static_cast<int>(where);
return -1;
}
inline int Bits::FindLSBSetNonZero(uint32 n) {
assert(n != 0);
unsigned long where;
if (_BitScanForward(&where, n))
return static_cast<int>(where);
return 32;
}
#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
inline int Bits::FindLSBSetNonZero64(uint64 n) {
assert(n != 0);
unsigned long where;
if (_BitScanForward64(&where, n))
return static_cast<int>(where);
return 64;
}
#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
#else // Portable versions.
inline int Bits::Log2Floor(uint32 n) {
if (n == 0)
return -1;
inline int Bits::Log2FloorNonZero(uint32 n) {
assert(n != 0);
int log = 0;
uint32 value = n;
for (int i = 4; i >= 0; --i) {
@ -400,7 +468,13 @@ inline int Bits::Log2Floor(uint32 n) {
return log;
}
inline int Bits::Log2Floor(uint32 n) {
return (n == 0) ? -1 : Bits::Log2FloorNonZero(n);
}
inline int Bits::FindLSBSetNonZero(uint32 n) {
assert(n != 0);
int rc = 31;
for (int i = 4, shift = 1 << 4; i >= 0; --i) {
const uint32 x = n << shift;
@ -413,8 +487,11 @@ inline int Bits::FindLSBSetNonZero(uint32 n) {
return rc;
}
#if defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
// FindLSBSetNonZero64() is defined in terms of FindLSBSetNonZero().
inline int Bits::FindLSBSetNonZero64(uint64 n) {
assert(n != 0);
const uint32 bottombits = static_cast<uint32>(n);
if (bottombits == 0) {
// Bottom bits are zero, so scan in top bits
@ -423,6 +500,7 @@ inline int Bits::FindLSBSetNonZero64(uint64 n) {
return FindLSBSetNonZero(bottombits);
}
}
#endif // defined(ARCH_K8) || defined(ARCH_PPC) || defined(ARCH_ARM)
#endif // End portable versions.
@ -446,7 +524,7 @@ class Varint {
static char* Encode32(char* ptr, uint32 v);
// EFFECTS Appends the varint representation of "value" to "*s".
static void Append32(string* s, uint32 value);
static void Append32(std::string* s, uint32 value);
};
inline const char* Varint::Parse32WithLimit(const char* p,
@ -503,7 +581,7 @@ inline char* Varint::Encode32(char* sptr, uint32 v) {
// replace this function with one that resizes the string without
// filling the new space with zeros (if applicable) --
// it will be non-portable but faster.
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
inline void STLStringResizeUninitialized(std::string* s, size_t new_size) {
s->resize(new_size);
}
@ -519,7 +597,7 @@ inline void STLStringResizeUninitialized(string* s, size_t new_size) {
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-defects.html#530)
// proposes this as the method. It will officially be part of the standard
// for C++0x. This should already work on all current implementations.
inline char* string_as_array(string* str) {
inline char* string_as_array(std::string* str) {
return str->empty() ? NULL : &*str->begin();
}

Просмотреть файл

@ -1,5 +1,4 @@
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: sesse@google.com (Steinar H. Gunderson)
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
@ -36,64 +35,39 @@
#ifndef THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
#define THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_STUBS_PUBLIC_H_
#if @ac_cv_have_stdint_h@
#include <stdint.h>
#endif
#include <cstddef>
#include <cstdint>
#include <string>
#if @ac_cv_have_stddef_h@
#include <stddef.h>
#endif
#if @ac_cv_have_sys_uio_h@
#if ${HAVE_SYS_UIO_H_01} // HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#endif // HAVE_SYS_UIO_H
#define SNAPPY_MAJOR @SNAPPY_MAJOR@
#define SNAPPY_MINOR @SNAPPY_MINOR@
#define SNAPPY_PATCHLEVEL @SNAPPY_PATCHLEVEL@
#define SNAPPY_MAJOR ${PROJECT_VERSION_MAJOR}
#define SNAPPY_MINOR ${PROJECT_VERSION_MINOR}
#define SNAPPY_PATCHLEVEL ${PROJECT_VERSION_PATCH}
#define SNAPPY_VERSION \
((SNAPPY_MAJOR << 16) | (SNAPPY_MINOR << 8) | SNAPPY_PATCHLEVEL)
#include <string>
namespace snappy {
#if @ac_cv_have_stdint_h@
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#else
typedef signed char int8;
typedef unsigned char uint8;
typedef short int16;
typedef unsigned short uint16;
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
#endif
using int8 = std::int8_t;
using uint8 = std::uint8_t;
using int16 = std::int16_t;
using uint16 = std::uint16_t;
using int32 = std::int32_t;
using uint32 = std::uint32_t;
using int64 = std::int64_t;
using uint64 = std::uint64_t;
typedef std::string string;
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
#if !@ac_cv_have_sys_uio_h@
#if !${HAVE_SYS_UIO_H_01} // !HAVE_SYS_UIO_H
// Windows does not have an iovec type, yet the concept is universally useful.
// It is simple to define it ourselves, so we put it inside our own namespace.
struct iovec {
void* iov_base;
size_t iov_len;
void* iov_base;
size_t iov_len;
};
#endif
#endif // !HAVE_SYS_UIO_H
} // namespace snappy

Просмотреть файл

@ -33,6 +33,9 @@
#endif
#ifdef HAVE_WINDOWS_H
// Needed to be able to use std::max without workarounds in the source code.
// https://support.microsoft.com/en-us/help/143208/prb-using-stl-in-windows-program-can-cause-min-max-conflicts
#define NOMINMAX
#include <windows.h>
#endif
@ -45,12 +48,12 @@ DEFINE_bool(run_microbenchmarks, true,
namespace snappy {
string ReadTestDataFile(const string& base, size_t size_limit) {
string contents;
std::string ReadTestDataFile(const std::string& base, size_t size_limit) {
std::string contents;
const char* srcdir = getenv("srcdir"); // This is set by Automake.
string prefix;
std::string prefix;
if (srcdir) {
prefix = string(srcdir) + "/";
prefix = std::string(srcdir) + "/";
}
file::GetContents(prefix + "testdata/" + base, &contents, file::Defaults()
).CheckSuccess();
@ -60,11 +63,11 @@ string ReadTestDataFile(const string& base, size_t size_limit) {
return contents;
}
string ReadTestDataFile(const string& base) {
std::string ReadTestDataFile(const std::string& base) {
return ReadTestDataFile(base, 0);
}
string StringPrintf(const char* format, ...) {
std::string StrFormat(const char* format, ...) {
char buf[4096];
va_list ap;
va_start(ap, format);
@ -76,7 +79,7 @@ string StringPrintf(const char* format, ...) {
bool benchmark_running = false;
int64 benchmark_real_time_us = 0;
int64 benchmark_cpu_time_us = 0;
string *benchmark_label = NULL;
std::string* benchmark_label = nullptr;
int64 benchmark_bytes_processed = 0;
void ResetBenchmarkTiming() {
@ -160,11 +163,11 @@ void StopBenchmarkTiming() {
benchmark_running = false;
}
void SetBenchmarkLabel(const string& str) {
void SetBenchmarkLabel(const std::string& str) {
if (benchmark_label) {
delete benchmark_label;
}
benchmark_label = new string(str);
benchmark_label = new std::string(str);
}
void SetBenchmarkBytesProcessed(int64 bytes) {
@ -201,7 +204,7 @@ void Benchmark::Run() {
if (benchmark_real_time_us > 0) {
num_iterations = 200000 * kCalibrateIterations / benchmark_real_time_us;
}
num_iterations = max(num_iterations, kCalibrateIterations);
num_iterations = std::max(num_iterations, kCalibrateIterations);
BenchmarkRun benchmark_runs[kNumRuns];
for (int run = 0; run < kNumRuns; ++run) {
@ -214,13 +217,13 @@ void Benchmark::Run() {
benchmark_runs[run].cpu_time_us = benchmark_cpu_time_us;
}
string heading = StringPrintf("%s/%d", name_.c_str(), test_case_num);
string human_readable_speed;
std::string heading = StrFormat("%s/%d", name_.c_str(), test_case_num);
std::string human_readable_speed;
nth_element(benchmark_runs,
benchmark_runs + kMedianPos,
benchmark_runs + kNumRuns,
BenchmarkCompareCPUTime());
std::nth_element(benchmark_runs,
benchmark_runs + kMedianPos,
benchmark_runs + kNumRuns,
BenchmarkCompareCPUTime());
int64 real_time_us = benchmark_runs[kMedianPos].real_time_us;
int64 cpu_time_us = benchmark_runs[kMedianPos].cpu_time_us;
if (cpu_time_us <= 0) {
@ -229,15 +232,16 @@ void Benchmark::Run() {
int64 bytes_per_second =
benchmark_bytes_processed * 1000000 / cpu_time_us;
if (bytes_per_second < 1024) {
human_readable_speed = StringPrintf("%dB/s", bytes_per_second);
human_readable_speed =
StrFormat("%dB/s", static_cast<int>(bytes_per_second));
} else if (bytes_per_second < 1024 * 1024) {
human_readable_speed = StringPrintf(
human_readable_speed = StrFormat(
"%.1fkB/s", bytes_per_second / 1024.0f);
} else if (bytes_per_second < 1024 * 1024 * 1024) {
human_readable_speed = StringPrintf(
human_readable_speed = StrFormat(
"%.1fMB/s", bytes_per_second / (1024.0f * 1024.0f));
} else {
human_readable_speed = StringPrintf(
human_readable_speed = StrFormat(
"%.1fGB/s", bytes_per_second / (1024.0f * 1024.0f * 1024.0f));
}
}
@ -523,8 +527,8 @@ int ZLib::UncompressAtMostOrAll(Bytef *dest, uLongf *destLen,
LOG(WARNING)
<< "UncompressChunkOrAll: Received some extra data, bytes total: "
<< uncomp_stream_.avail_in << " bytes: "
<< string(reinterpret_cast<const char *>(uncomp_stream_.next_in),
min(int(uncomp_stream_.avail_in), 20));
<< std::string(reinterpret_cast<const char *>(uncomp_stream_.next_in),
std::min(int(uncomp_stream_.avail_in), 20));
UncompressErrorInit();
return Z_DATA_ERROR; // what's the extra data for?
} else if (err != Z_OK && err != Z_STREAM_END && err != Z_BUF_ERROR) {

Просмотреть файл

@ -55,8 +55,6 @@
#include <windows.h>
#endif
#include <string>
#ifdef HAVE_GTEST
#include <gtest/gtest.h>
@ -110,26 +108,8 @@
#include "lzo/lzo1x.h"
#endif
#ifdef HAVE_LIBLZF
extern "C" {
#include "lzf.h"
}
#endif
#ifdef HAVE_LIBFASTLZ
#include "fastlz.h"
#endif
#ifdef HAVE_LIBQUICKLZ
#include "quicklz.h"
#endif
namespace {
namespace File {
void Init() { }
} // namespace File
namespace file {
int Defaults() { return 0; }
@ -138,7 +118,8 @@ namespace file {
void CheckSuccess() { }
};
DummyStatus GetContents(const string& filename, string* data, int unused) {
DummyStatus GetContents(
const std::string& filename, std::string* data, int unused) {
FILE* fp = fopen(filename.c_str(), "rb");
if (fp == NULL) {
perror(filename.c_str());
@ -153,7 +134,7 @@ namespace file {
perror("fread");
exit(1);
}
data->append(string(buf, ret));
data->append(std::string(buf, ret));
}
fclose(fp);
@ -161,9 +142,8 @@ namespace file {
return DummyStatus();
}
DummyStatus SetContents(const string& filename,
const string& str,
int unused) {
inline DummyStatus SetContents(
const std::string& filename, const std::string& str, int unused) {
FILE* fp = fopen(filename.c_str(), "wb");
if (fp == NULL) {
perror(filename.c_str());
@ -187,7 +167,7 @@ namespace file {
namespace snappy {
#define FLAGS_test_random_seed 301
typedef string TypeParam;
using TypeParam = std::string;
void Test_CorruptedTest_VerifyCorrupted();
void Test_Snappy_SimpleTests();
@ -201,63 +181,13 @@ void Test_Snappy_ReadPastEndOfBuffer();
void Test_Snappy_FindMatchLength();
void Test_Snappy_FindMatchLengthRandom();
string ReadTestDataFile(const string& base, size_t size_limit);
std::string ReadTestDataFile(const std::string& base, size_t size_limit);
string ReadTestDataFile(const string& base);
std::string ReadTestDataFile(const std::string& base);
// A sprintf() variant that returns a std::string.
// Not safe for general use due to truncation issues.
string StringPrintf(const char* format, ...);
// A simple, non-cryptographically-secure random generator.
class ACMRandom {
public:
explicit ACMRandom(uint32 seed) : seed_(seed) {}
int32 Next();
int32 Uniform(int32 n) {
return Next() % n;
}
uint8 Rand8() {
return static_cast<uint8>((Next() >> 1) & 0x000000ff);
}
bool OneIn(int X) { return Uniform(X) == 0; }
// Skewed: pick "base" uniformly from range [0,max_log] and then
// return "base" random bits. The effect is to pick a number in the
// range [0,2^max_log-1] with bias towards smaller numbers.
int32 Skewed(int max_log);
private:
static const uint32 M = 2147483647L; // 2^31-1
uint32 seed_;
};
inline int32 ACMRandom::Next() {
static const uint64 A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
// We are computing
// seed_ = (seed_ * A) % M, where M = 2^31-1
//
// seed_ must not be zero or M, or else all subsequent computed values
// will be zero or M respectively. For all other values, seed_ will end
// up cycling through every number in [1,M-1]
uint64 product = seed_ * A;
// Compute (product % M) using the fact that ((x << 31) % M) == x.
seed_ = (product >> 31) + (product & M);
// The first reduction may overflow by 1 bit, so we may need to repeat.
// mod == M is not possible; using > allows the faster sign-bit-based test.
if (seed_ > M) {
seed_ -= M;
}
return seed_;
}
inline int32 ACMRandom::Skewed(int max_log) {
const int32 base = (Next() - 1) % (max_log+1);
return (Next() - 1) & ((1u << base)-1);
}
std::string StrFormat(const char* format, ...);
// A wall-time clock. This stub is not super-accurate, nor resistant to the
// system time changing.
@ -311,8 +241,8 @@ typedef void (*BenchmarkFunction)(int, int);
class Benchmark {
public:
Benchmark(const string& name, BenchmarkFunction function) :
name_(name), function_(function) {}
Benchmark(const std::string& name, BenchmarkFunction function)
: name_(name), function_(function) {}
Benchmark* DenseRange(int start, int stop) {
start_ = start;
@ -323,7 +253,7 @@ class Benchmark {
void Run();
private:
const string name_;
const std::string name_;
const BenchmarkFunction function_;
int start_, stop_;
};
@ -335,11 +265,13 @@ extern Benchmark* Benchmark_BM_UFlat;
extern Benchmark* Benchmark_BM_UIOVec;
extern Benchmark* Benchmark_BM_UValidate;
extern Benchmark* Benchmark_BM_ZFlat;
extern Benchmark* Benchmark_BM_ZFlatAll;
extern Benchmark* Benchmark_BM_ZFlatIncreasingTableSize;
void ResetBenchmarkTiming();
void StartBenchmarkTiming();
void StopBenchmarkTiming();
void SetBenchmarkLabel(const string& str);
void SetBenchmarkLabel(const std::string& str);
void SetBenchmarkBytesProcessed(int64 bytes);
#ifdef HAVE_LIBZ
@ -467,7 +399,7 @@ class ZLib {
DECLARE_bool(run_microbenchmarks);
static void RunSpecifiedBenchmarks() {
static inline void RunSpecifiedBenchmarks() {
if (!FLAGS_run_microbenchmarks) {
return;
}
@ -486,6 +418,8 @@ static void RunSpecifiedBenchmarks() {
snappy::Benchmark_BM_UIOVec->Run();
snappy::Benchmark_BM_UValidate->Run();
snappy::Benchmark_BM_ZFlat->Run();
snappy::Benchmark_BM_ZFlatAll->Run();
snappy::Benchmark_BM_ZFlatIncreasingTableSize->Run();
fprintf(stderr, "\n");
}
@ -515,10 +449,6 @@ static inline int RUN_ALL_TESTS() {
// For main().
namespace snappy {
static void CompressFile(const char* fname);
static void UncompressFile(const char* fname);
static void MeasureFile(const char* fname);
// Logging.
#define LOG(level) LogMessage()
@ -529,15 +459,15 @@ class LogMessage {
public:
LogMessage() { }
~LogMessage() {
cerr << endl;
std::cerr << std::endl;
}
LogMessage& operator<<(const std::string& msg) {
cerr << msg;
std::cerr << msg;
return *this;
}
LogMessage& operator<<(int x) {
cerr << x;
std::cerr << x;
return *this;
}
};
@ -546,7 +476,7 @@ class LogMessage {
// and ones that are always active.
#define CRASH_UNLESS(condition) \
PREDICT_TRUE(condition) ? (void)0 : \
SNAPPY_PREDICT_TRUE(condition) ? (void)0 : \
snappy::LogMessageVoidify() & snappy::LogMessageCrash()
#ifdef _MSC_VER
@ -560,7 +490,7 @@ class LogMessageCrash : public LogMessage {
public:
LogMessageCrash() { }
~LogMessageCrash() {
cerr << endl;
std::cerr << std::endl;
abort();
}
};
@ -590,10 +520,6 @@ class LogMessageVoidify {
#define CHECK_GT(a, b) CRASH_UNLESS((a) > (b))
#define CHECK_OK(cond) (cond).CheckSuccess()
} // namespace
using snappy::CompressFile;
using snappy::UncompressFile;
using snappy::MeasureFile;
} // namespace snappy
#endif // THIRD_PARTY_SNAPPY_OPENSOURCE_SNAPPY_TEST_H_

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -39,7 +39,7 @@
#ifndef THIRD_PARTY_SNAPPY_SNAPPY_H__
#define THIRD_PARTY_SNAPPY_SNAPPY_H__
#include <stddef.h>
#include <cstddef>
#include <string>
#include "snappy-stubs-public.h"
@ -69,11 +69,12 @@ namespace snappy {
// Higher-level string based routines (should be sufficient for most users)
// ------------------------------------------------------------------------
// Sets "*output" to the compressed version of "input[0,input_length-1]".
// Original contents of *output are lost.
// Sets "*compressed" to the compressed version of "input[0,input_length-1]".
// Original contents of *compressed are lost.
//
// REQUIRES: "input[]" is not an alias of "*output".
size_t Compress(const char* input, size_t input_length, string* output);
// REQUIRES: "input[]" is not an alias of "*compressed".
size_t Compress(const char* input, size_t input_length,
std::string* compressed);
// Decompresses "compressed[0,compressed_length-1]" to "*uncompressed".
// Original contents of "*uncompressed" are lost.
@ -82,7 +83,7 @@ namespace snappy {
//
// returns false if the message is corrupted and could not be decompressed
bool Uncompress(const char* compressed, size_t compressed_length,
string* uncompressed);
std::string* uncompressed);
// Decompresses "compressed" to "*uncompressed".
//
@ -193,11 +194,14 @@ namespace snappy {
// Note that there might be older data around that is compressed with larger
// block sizes, so the decompression code should not rely on the
// non-existence of long backreferences.
static const int kBlockLog = 16;
static const size_t kBlockSize = 1 << kBlockLog;
static constexpr int kBlockLog = 16;
static constexpr size_t kBlockSize = 1 << kBlockLog;
static const int kMaxHashTableBits = 14;
static const size_t kMaxHashTableSize = 1 << kMaxHashTableBits;
static constexpr int kMinHashTableBits = 8;
static constexpr size_t kMinHashTableSize = 1 << kMinHashTableBits;
static constexpr int kMaxHashTableBits = 14;
static constexpr size_t kMaxHashTableSize = 1 << kMaxHashTableBits;
} // end namespace snappy
#endif // THIRD_PARTY_SNAPPY_SNAPPY_H__

Просмотреть файл

@ -0,0 +1,59 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// libFuzzer harness for fuzzing snappy compression code.
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <string>
#include "snappy.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::string input(reinterpret_cast<const char*>(data), size);
std::string compressed;
size_t compressed_size =
snappy::Compress(input.data(), input.size(), &compressed);
(void)compressed_size; // Variable only used in debug builds.
assert(compressed_size == compressed.size());
assert(compressed.size() <= snappy::MaxCompressedLength(input.size()));
assert(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size()));
std::string uncompressed_after_compress;
bool uncompress_succeeded = snappy::Uncompress(
compressed.data(), compressed.size(), &uncompressed_after_compress);
(void)uncompress_succeeded; // Variable only used in debug builds.
assert(uncompress_succeeded);
assert(input == uncompressed_after_compress);
return 0;
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// libFuzzer harness for fuzzing snappy's decompression code.
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <string>
#include "snappy.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
std::string input(reinterpret_cast<const char*>(data), size);
// Avoid self-crafted decompression bombs.
size_t uncompressed_size;
constexpr size_t kMaxUncompressedSize = 1 << 20;
bool get_uncompressed_length_succeeded = snappy::GetUncompressedLength(
input.data(), input.size(), &uncompressed_size);
if (!get_uncompressed_length_succeeded ||
(uncompressed_size > kMaxUncompressedSize)) {
return 0;
}
std::string uncompressed;
// The return value of snappy::Uncompress() is ignored because decompression
// will fail on invalid inputs.
snappy::Uncompress(input.data(), input.size(), &uncompressed);
return 0;
}

Просмотреть файл

@ -29,9 +29,10 @@
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include <random>
#include <string>
#include <utility>
#include <vector>
#include "snappy.h"
@ -50,13 +51,6 @@ DEFINE_bool(zlib, false,
"Run zlib compression (http://www.zlib.net)");
DEFINE_bool(lzo, false,
"Run LZO compression (http://www.oberhumer.com/opensource/lzo/)");
DEFINE_bool(quicklz, false,
"Run quickLZ compression (http://www.quicklz.com/)");
DEFINE_bool(liblzf, false,
"Run libLZF compression "
"(http://www.goof.com/pcg/marc/liblzf.html)");
DEFINE_bool(fastlz, false,
"Run FastLZ compression (http://www.fastlz.org/");
DEFINE_bool(snappy, true, "Run snappy compression");
DEFINE_bool(write_compressed, false,
@ -69,8 +63,7 @@ DEFINE_bool(snappy_dump_decompression_table, false,
namespace snappy {
#ifdef HAVE_FUNC_MMAP
#if defined(HAVE_FUNC_MMAP) && defined(HAVE_FUNC_SYSCONF)
// To test against code that reads beyond its input, this class copies a
// string to a newly allocated group of pages, the last of which
@ -80,8 +73,8 @@ namespace snappy {
// be able to read previously allocated memory while doing heap allocations.
class DataEndingAtUnreadablePage {
public:
explicit DataEndingAtUnreadablePage(const string& s) {
const size_t page_size = getpagesize();
explicit DataEndingAtUnreadablePage(const std::string& s) {
const size_t page_size = sysconf(_SC_PAGESIZE);
const size_t size = s.size();
// Round up space for string to a multiple of page_size.
size_t space_for_string = (size + page_size - 1) & ~(page_size - 1);
@ -99,8 +92,9 @@ class DataEndingAtUnreadablePage {
}
~DataEndingAtUnreadablePage() {
const size_t page_size = sysconf(_SC_PAGESIZE);
// Undo the mprotect.
CHECK_EQ(0, mprotect(protected_page_, getpagesize(), PROT_READ|PROT_WRITE));
CHECK_EQ(0, mprotect(protected_page_, page_size, PROT_READ|PROT_WRITE));
CHECK_EQ(0, munmap(mem_, alloc_size_));
}
@ -115,19 +109,19 @@ class DataEndingAtUnreadablePage {
size_t size_;
};
#else // HAVE_FUNC_MMAP
#else // defined(HAVE_FUNC_MMAP) && defined(HAVE_FUNC_SYSCONF)
// Fallback for systems without mmap.
typedef string DataEndingAtUnreadablePage;
using DataEndingAtUnreadablePage = std::string;
#endif
enum CompressorType {
ZLIB, LZO, LIBLZF, QUICKLZ, FASTLZ, SNAPPY
ZLIB, LZO, SNAPPY
};
const char* names[] = {
"ZLIB", "LZO", "LIBLZF", "QUICKLZ", "FASTLZ", "SNAPPY"
"ZLIB", "LZO", "SNAPPY"
};
static size_t MinimumRequiredOutputSpace(size_t input_size,
@ -143,21 +137,6 @@ static size_t MinimumRequiredOutputSpace(size_t input_size,
return input_size + input_size/64 + 16 + 3;
#endif // LZO_VERSION
#ifdef LZF_VERSION
case LIBLZF:
return input_size;
#endif // LZF_VERSION
#ifdef QLZ_VERSION_MAJOR
case QUICKLZ:
return input_size + 36000; // 36000 is used for scratch.
#endif // QLZ_VERSION_MAJOR
#ifdef FASTLZ_VERSION
case FASTLZ:
return max(static_cast<int>(ceil(input_size * 1.05)), 66);
#endif // FASTLZ_VERSION
case SNAPPY:
return snappy::MaxCompressedLength(input_size);
@ -175,7 +154,7 @@ static size_t MinimumRequiredOutputSpace(size_t input_size,
// "compressed" must be preinitialized to at least MinCompressbufSize(comp)
// number of bytes, and may contain junk bytes at the end after return.
static bool Compress(const char* input, size_t input_size, CompressorType comp,
string* compressed, bool compressed_is_preallocated) {
std::string* compressed, bool compressed_is_preallocated) {
if (!compressed_is_preallocated) {
compressed->resize(MinimumRequiredOutputSpace(input_size, comp));
}
@ -217,58 +196,6 @@ static bool Compress(const char* input, size_t input_size, CompressorType comp,
}
#endif // LZO_VERSION
#ifdef LZF_VERSION
case LIBLZF: {
int destlen = lzf_compress(input,
input_size,
string_as_array(compressed),
input_size);
if (destlen == 0) {
// lzf *can* cause lots of blowup when compressing, so they
// recommend to limit outsize to insize, and just not compress
// if it's bigger. Ideally, we'd just swap input and output.
compressed->assign(input, input_size);
destlen = input_size;
}
if (!compressed_is_preallocated) {
compressed->resize(destlen);
}
break;
}
#endif // LZF_VERSION
#ifdef QLZ_VERSION_MAJOR
case QUICKLZ: {
qlz_state_compress *state_compress = new qlz_state_compress;
int destlen = qlz_compress(input,
string_as_array(compressed),
input_size,
state_compress);
delete state_compress;
CHECK_NE(0, destlen);
if (!compressed_is_preallocated) {
compressed->resize(destlen);
}
break;
}
#endif // QLZ_VERSION_MAJOR
#ifdef FASTLZ_VERSION
case FASTLZ: {
// Use level 1 compression since we mostly care about speed.
int destlen = fastlz_compress_level(
1,
input,
input_size,
string_as_array(compressed));
if (!compressed_is_preallocated) {
compressed->resize(destlen);
}
CHECK_NE(destlen, 0);
break;
}
#endif // FASTLZ_VERSION
case SNAPPY: {
size_t destlen;
snappy::RawCompress(input, input_size,
@ -288,8 +215,8 @@ static bool Compress(const char* input, size_t input_size, CompressorType comp,
return true;
}
static bool Uncompress(const string& compressed, CompressorType comp,
int size, string* output) {
static bool Uncompress(const std::string& compressed, CompressorType comp,
int size, std::string* output) {
switch (comp) {
#ifdef ZLIB_VERSION
case ZLIB: {
@ -323,49 +250,6 @@ static bool Uncompress(const string& compressed, CompressorType comp,
}
#endif // LZO_VERSION
#ifdef LZF_VERSION
case LIBLZF: {
output->resize(size);
int destlen = lzf_decompress(compressed.data(),
compressed.size(),
string_as_array(output),
output->size());
if (destlen == 0) {
// This error probably means we had decided not to compress,
// and thus have stored input in output directly.
output->assign(compressed.data(), compressed.size());
destlen = compressed.size();
}
CHECK_EQ(destlen, size);
break;
}
#endif // LZF_VERSION
#ifdef QLZ_VERSION_MAJOR
case QUICKLZ: {
output->resize(size);
qlz_state_decompress *state_decompress = new qlz_state_decompress;
int destlen = qlz_decompress(compressed.data(),
string_as_array(output),
state_decompress);
delete state_decompress;
CHECK_EQ(destlen, size);
break;
}
#endif // QLZ_VERSION_MAJOR
#ifdef FASTLZ_VERSION
case FASTLZ: {
output->resize(size);
int destlen = fastlz_decompress(compressed.data(),
compressed.length(),
string_as_array(output),
size);
CHECK_EQ(destlen, size);
break;
}
#endif // FASTLZ_VERSION
case SNAPPY: {
snappy::RawUncompress(compressed.data(), compressed.size(),
string_as_array(output));
@ -393,13 +277,13 @@ static void Measure(const char* data,
{
// Chop the input into blocks
int num_blocks = (length + block_size - 1) / block_size;
vector<const char*> input(num_blocks);
vector<size_t> input_length(num_blocks);
vector<string> compressed(num_blocks);
vector<string> output(num_blocks);
std::vector<const char*> input(num_blocks);
std::vector<size_t> input_length(num_blocks);
std::vector<std::string> compressed(num_blocks);
std::vector<std::string> output(num_blocks);
for (int b = 0; b < num_blocks; b++) {
int input_start = b * block_size;
int input_limit = min<int>((b+1)*block_size, length);
int input_limit = std::min<int>((b+1)*block_size, length);
input[b] = data+input_start;
input_length[b] = input_limit-input_start;
@ -454,29 +338,28 @@ static void Measure(const char* data,
}
}
sort(ctime, ctime + kRuns);
sort(utime, utime + kRuns);
std::sort(ctime, ctime + kRuns);
std::sort(utime, utime + kRuns);
const int med = kRuns/2;
float comp_rate = (length / ctime[med]) * repeats / 1048576.0;
float uncomp_rate = (length / utime[med]) * repeats / 1048576.0;
string x = names[comp];
std::string x = names[comp];
x += ":";
string urate = (uncomp_rate >= 0)
? StringPrintf("%.1f", uncomp_rate)
: string("?");
std::string urate = (uncomp_rate >= 0) ? StrFormat("%.1f", uncomp_rate)
: std::string("?");
printf("%-7s [b %dM] bytes %6d -> %6d %4.1f%% "
"comp %5.1f MB/s uncomp %5s MB/s\n",
x.c_str(),
block_size/(1<<20),
static_cast<int>(length), static_cast<uint32>(compressed_size),
(compressed_size * 100.0) / max<int>(1, length),
(compressed_size * 100.0) / std::max<int>(1, length),
comp_rate,
urate.c_str());
}
static int VerifyString(const string& input) {
string compressed;
static int VerifyString(const std::string& input) {
std::string compressed;
DataEndingAtUnreadablePage i(input);
const size_t written = snappy::Compress(i.data(), i.size(), &compressed);
CHECK_EQ(written, compressed.size());
@ -484,15 +367,15 @@ static int VerifyString(const string& input) {
snappy::MaxCompressedLength(input.size()));
CHECK(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size()));
string uncompressed;
std::string uncompressed;
DataEndingAtUnreadablePage c(compressed);
CHECK(snappy::Uncompress(c.data(), c.size(), &uncompressed));
CHECK_EQ(uncompressed, input);
return uncompressed.size();
}
static void VerifyStringSink(const string& input) {
string compressed;
static void VerifyStringSink(const std::string& input) {
std::string compressed;
DataEndingAtUnreadablePage i(input);
const size_t written = snappy::Compress(i.data(), i.size(), &compressed);
CHECK_EQ(written, compressed.size());
@ -500,7 +383,7 @@ static void VerifyStringSink(const string& input) {
snappy::MaxCompressedLength(input.size()));
CHECK(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size()));
string uncompressed;
std::string uncompressed;
uncompressed.resize(input.size());
snappy::UncheckedByteArraySink sink(string_as_array(&uncompressed));
DataEndingAtUnreadablePage c(compressed);
@ -509,8 +392,8 @@ static void VerifyStringSink(const string& input) {
CHECK_EQ(uncompressed, input);
}
static void VerifyIOVec(const string& input) {
string compressed;
static void VerifyIOVec(const std::string& input) {
std::string compressed;
DataEndingAtUnreadablePage i(input);
const size_t written = snappy::Compress(i.data(), i.size(), &compressed);
CHECK_EQ(written, compressed.size());
@ -521,23 +404,28 @@ static void VerifyIOVec(const string& input) {
// Try uncompressing into an iovec containing a random number of entries
// ranging from 1 to 10.
char* buf = new char[input.size()];
ACMRandom rnd(input.size());
size_t num = rnd.Next() % 10 + 1;
std::minstd_rand0 rng(input.size());
std::uniform_int_distribution<size_t> uniform_1_to_10(1, 10);
size_t num = uniform_1_to_10(rng);
if (input.size() < num) {
num = input.size();
}
struct iovec* iov = new iovec[num];
int used_so_far = 0;
std::bernoulli_distribution one_in_five(1.0 / 5);
for (size_t i = 0; i < num; ++i) {
assert(used_so_far < input.size());
iov[i].iov_base = buf + used_so_far;
if (i == num - 1) {
iov[i].iov_len = input.size() - used_so_far;
} else {
// Randomly choose to insert a 0 byte entry.
if (rnd.OneIn(5)) {
if (one_in_five(rng)) {
iov[i].iov_len = 0;
} else {
iov[i].iov_len = rnd.Uniform(input.size());
std::uniform_int_distribution<size_t> uniform_not_used_so_far(
0, input.size() - used_so_far - 1);
iov[i].iov_len = uniform_not_used_so_far(rng);
}
}
used_so_far += iov[i].iov_len;
@ -551,22 +439,22 @@ static void VerifyIOVec(const string& input) {
// Test that data compressed by a compressor that does not
// obey block sizes is uncompressed properly.
static void VerifyNonBlockedCompression(const string& input) {
static void VerifyNonBlockedCompression(const std::string& input) {
if (input.length() > snappy::kBlockSize) {
// We cannot test larger blocks than the maximum block size, obviously.
return;
}
string prefix;
std::string prefix;
Varint::Append32(&prefix, input.size());
// Setup compression table
snappy::internal::WorkingMemory wmem;
snappy::internal::WorkingMemory wmem(input.size());
int table_size;
uint16* table = wmem.GetHashTable(input.size(), &table_size);
// Compress entire input in one shot
string compressed;
std::string compressed;
compressed += prefix;
compressed.resize(prefix.size()+snappy::MaxCompressedLength(input.size()));
char* dest = string_as_array(&compressed) + prefix.size();
@ -574,13 +462,13 @@ static void VerifyNonBlockedCompression(const string& input) {
dest, table, table_size);
compressed.resize(end - compressed.data());
// Uncompress into string
string uncomp_str;
// Uncompress into std::string
std::string uncomp_str;
CHECK(snappy::Uncompress(compressed.data(), compressed.size(), &uncomp_str));
CHECK_EQ(uncomp_str, input);
// Uncompress using source/sink
string uncomp_str2;
std::string uncomp_str2;
uncomp_str2.resize(input.size());
snappy::UncheckedByteArraySink sink(string_as_array(&uncomp_str2));
snappy::ByteArraySource source(compressed.data(), compressed.size());
@ -592,28 +480,28 @@ static void VerifyNonBlockedCompression(const string& input) {
static const int kNumBlocks = 10;
struct iovec vec[kNumBlocks];
const int block_size = 1 + input.size() / kNumBlocks;
string iovec_data(block_size * kNumBlocks, 'x');
std::string iovec_data(block_size * kNumBlocks, 'x');
for (int i = 0; i < kNumBlocks; i++) {
vec[i].iov_base = string_as_array(&iovec_data) + i * block_size;
vec[i].iov_len = block_size;
}
CHECK(snappy::RawUncompressToIOVec(compressed.data(), compressed.size(),
vec, kNumBlocks));
CHECK_EQ(string(iovec_data.data(), input.size()), input);
CHECK_EQ(std::string(iovec_data.data(), input.size()), input);
}
}
// Expand the input so that it is at least K times as big as block size
static string Expand(const string& input) {
static std::string Expand(const std::string& input) {
static const int K = 3;
string data = input;
std::string data = input;
while (data.size() < K * snappy::kBlockSize) {
data += input;
}
return data;
}
static int Verify(const string& input) {
static int Verify(const std::string& input) {
VLOG(1) << "Verifying input of size " << input.size();
// Compress using string based routines
@ -625,7 +513,7 @@ static int Verify(const string& input) {
VerifyNonBlockedCompression(input);
VerifyIOVec(input);
if (!input.empty()) {
const string expanded = Expand(input);
const std::string expanded = Expand(input);
VerifyNonBlockedCompression(expanded);
VerifyIOVec(input);
}
@ -633,21 +521,20 @@ static int Verify(const string& input) {
return result;
}
static bool IsValidCompressedBuffer(const string& c) {
static bool IsValidCompressedBuffer(const std::string& c) {
return snappy::IsValidCompressedBuffer(c.data(), c.size());
}
static bool Uncompress(const string& c, string* u) {
static bool Uncompress(const std::string& c, std::string* u) {
return snappy::Uncompress(c.data(), c.size(), u);
}
// This test checks to ensure that snappy doesn't coredump if it gets
// corrupted data.
TEST(CorruptedTest, VerifyCorrupted) {
string source = "making sure we don't crash with corrupted input";
std::string source = "making sure we don't crash with corrupted input";
VLOG(1) << source;
string dest;
string uncmp;
std::string dest;
std::string uncmp;
snappy::Compress(source.data(), source.size(), &dest);
// Mess around with the data. It's hard to simulate all possible
@ -694,9 +581,9 @@ TEST(CorruptedTest, VerifyCorrupted) {
// try reading stuff in from a bad file.
for (int i = 1; i <= 3; ++i) {
string data = ReadTestDataFile(StringPrintf("baddata%d.snappy", i).c_str(),
0);
string uncmp;
std::string data =
ReadTestDataFile(StrFormat("baddata%d.snappy", i).c_str(), 0);
std::string uncmp;
// check that we don't return a crazy length
size_t ulen;
CHECK(!snappy::GetUncompressedLength(data.data(), data.size(), &ulen)
@ -714,7 +601,7 @@ TEST(CorruptedTest, VerifyCorrupted) {
// These mirror the compression code in snappy.cc, but are copied
// here so that we can bypass some limitations in the how snappy.cc
// invokes these routines.
static void AppendLiteral(string* dst, const string& literal) {
static void AppendLiteral(std::string* dst, const std::string& literal) {
if (literal.empty()) return;
int n = literal.size() - 1;
if (n < 60) {
@ -729,12 +616,12 @@ static void AppendLiteral(string* dst, const string& literal) {
n >>= 8;
}
dst->push_back(0 | ((59+count) << 2));
*dst += string(number, count);
*dst += std::string(number, count);
}
*dst += literal;
}
static void AppendCopy(string* dst, int offset, int length) {
static void AppendCopy(std::string* dst, int offset, int length) {
while (length > 0) {
// Figure out how much to copy in one shot
int to_copy;
@ -771,51 +658,67 @@ TEST(Snappy, SimpleTests) {
Verify("ab");
Verify("abc");
Verify("aaaaaaa" + string(16, 'b') + string("aaaaa") + "abc");
Verify("aaaaaaa" + string(256, 'b') + string("aaaaa") + "abc");
Verify("aaaaaaa" + string(2047, 'b') + string("aaaaa") + "abc");
Verify("aaaaaaa" + string(65536, 'b') + string("aaaaa") + "abc");
Verify("abcaaaaaaa" + string(65536, 'b') + string("aaaaa") + "abc");
Verify("aaaaaaa" + std::string(16, 'b') + std::string("aaaaa") + "abc");
Verify("aaaaaaa" + std::string(256, 'b') + std::string("aaaaa") + "abc");
Verify("aaaaaaa" + std::string(2047, 'b') + std::string("aaaaa") + "abc");
Verify("aaaaaaa" + std::string(65536, 'b') + std::string("aaaaa") + "abc");
Verify("abcaaaaaaa" + std::string(65536, 'b') + std::string("aaaaa") + "abc");
}
// Verify max blowup (lots of four-byte copies)
TEST(Snappy, MaxBlowup) {
string input;
for (int i = 0; i < 20000; i++) {
ACMRandom rnd(i);
uint32 bytes = static_cast<uint32>(rnd.Next());
input.append(reinterpret_cast<char*>(&bytes), sizeof(bytes));
}
for (int i = 19999; i >= 0; i--) {
ACMRandom rnd(i);
uint32 bytes = static_cast<uint32>(rnd.Next());
input.append(reinterpret_cast<char*>(&bytes), sizeof(bytes));
std::mt19937 rng;
std::uniform_int_distribution<int> uniform_byte(0, 255);
std::string input;
for (int i = 0; i < 80000; ++i)
input.push_back(static_cast<char>(uniform_byte(rng)));
for (int i = 0; i < 80000; i += 4) {
std::string four_bytes(input.end() - i - 4, input.end() - i);
input.append(four_bytes);
}
Verify(input);
}
TEST(Snappy, RandomData) {
ACMRandom rnd(FLAGS_test_random_seed);
std::minstd_rand0 rng(FLAGS_test_random_seed);
std::uniform_int_distribution<int> uniform_0_to_3(0, 3);
std::uniform_int_distribution<int> uniform_0_to_8(0, 8);
std::uniform_int_distribution<int> uniform_byte(0, 255);
std::uniform_int_distribution<size_t> uniform_4k(0, 4095);
std::uniform_int_distribution<size_t> uniform_64k(0, 65535);
std::bernoulli_distribution one_in_ten(1.0 / 10);
const int num_ops = 20000;
constexpr int num_ops = 20000;
for (int i = 0; i < num_ops; i++) {
if ((i % 1000) == 0) {
VLOG(0) << "Random op " << i << " of " << num_ops;
}
string x;
size_t len = rnd.Uniform(4096);
std::string x;
size_t len = uniform_4k(rng);
if (i < 100) {
len = 65536 + rnd.Uniform(65536);
len = 65536 + uniform_64k(rng);
}
while (x.size() < len) {
int run_len = 1;
if (rnd.OneIn(10)) {
run_len = rnd.Skewed(8);
if (one_in_ten(rng)) {
int skewed_bits = uniform_0_to_8(rng);
// int is guaranteed to hold at least 16 bits, this uses at most 8 bits.
std::uniform_int_distribution<int> skewed_low(0,
(1 << skewed_bits) - 1);
run_len = skewed_low(rng);
}
char c = static_cast<char>(uniform_byte(rng));
if (i >= 100) {
int skewed_bits = uniform_0_to_3(rng);
// int is guaranteed to hold at least 16 bits, this uses at most 3 bits.
std::uniform_int_distribution<int> skewed_low(0,
(1 << skewed_bits) - 1);
c = static_cast<char>(skewed_low(rng));
}
char c = (i < 100) ? rnd.Uniform(256) : rnd.Skewed(3);
while (run_len-- > 0 && x.size() < len) {
x += c;
x.push_back(c);
}
}
@ -829,19 +732,19 @@ TEST(Snappy, FourByteOffset) {
// copy manually.
// The two fragments that make up the input string.
string fragment1 = "012345689abcdefghijklmnopqrstuvwxyz";
string fragment2 = "some other string";
std::string fragment1 = "012345689abcdefghijklmnopqrstuvwxyz";
std::string fragment2 = "some other string";
// How many times each fragment is emitted.
const int n1 = 2;
const int n2 = 100000 / fragment2.size();
const int length = n1 * fragment1.size() + n2 * fragment2.size();
string compressed;
std::string compressed;
Varint::Append32(&compressed, length);
AppendLiteral(&compressed, fragment1);
string src = fragment1;
std::string src = fragment1;
for (int i = 0; i < n2; i++) {
AppendLiteral(&compressed, fragment2);
src += fragment2;
@ -850,7 +753,7 @@ TEST(Snappy, FourByteOffset) {
src += fragment1;
CHECK_EQ(length, src.size());
string uncompressed;
std::string uncompressed;
CHECK(snappy::IsValidCompressedBuffer(compressed.data(), compressed.size()));
CHECK(snappy::Uncompress(compressed.data(), compressed.size(),
&uncompressed));
@ -872,7 +775,7 @@ TEST(Snappy, IOVecEdgeCases) {
iov[i].iov_len = kLengths[i];
}
string compressed;
std::string compressed;
Varint::Append32(&compressed, 22);
// A literal whose output crosses three blocks.
@ -933,7 +836,7 @@ TEST(Snappy, IOVecLiteralOverflow) {
iov[i].iov_len = kLengths[i];
}
string compressed;
std::string compressed;
Varint::Append32(&compressed, 8);
AppendLiteral(&compressed, "12345678");
@ -955,7 +858,7 @@ TEST(Snappy, IOVecCopyOverflow) {
iov[i].iov_len = kLengths[i];
}
string compressed;
std::string compressed;
Varint::Append32(&compressed, 8);
AppendLiteral(&compressed, "123");
@ -969,7 +872,7 @@ TEST(Snappy, IOVecCopyOverflow) {
}
}
static bool CheckUncompressedLength(const string& compressed,
static bool CheckUncompressedLength(const std::string& compressed,
size_t* ulength) {
const bool result1 = snappy::GetUncompressedLength(compressed.data(),
compressed.size(),
@ -983,7 +886,7 @@ static bool CheckUncompressedLength(const string& compressed,
}
TEST(SnappyCorruption, TruncatedVarint) {
string compressed, uncompressed;
std::string compressed, uncompressed;
size_t ulength;
compressed.push_back('\xf0');
CHECK(!CheckUncompressedLength(compressed, &ulength));
@ -993,7 +896,7 @@ TEST(SnappyCorruption, TruncatedVarint) {
}
TEST(SnappyCorruption, UnterminatedVarint) {
string compressed, uncompressed;
std::string compressed, uncompressed;
size_t ulength;
compressed.push_back('\x80');
compressed.push_back('\x80');
@ -1008,7 +911,7 @@ TEST(SnappyCorruption, UnterminatedVarint) {
}
TEST(SnappyCorruption, OverflowingVarint) {
string compressed, uncompressed;
std::string compressed, uncompressed;
size_t ulength;
compressed.push_back('\xfb');
compressed.push_back('\xff');
@ -1025,14 +928,14 @@ TEST(Snappy, ReadPastEndOfBuffer) {
// Check that we do not read past end of input
// Make a compressed string that ends with a single-byte literal
string compressed;
std::string compressed;
Varint::Append32(&compressed, 1);
AppendLiteral(&compressed, "x");
string uncompressed;
std::string uncompressed;
DataEndingAtUnreadablePage c(compressed);
CHECK(snappy::Uncompress(c.data(), c.size(), &uncompressed));
CHECK_EQ(uncompressed, string("x"));
CHECK_EQ(uncompressed, std::string("x"));
}
// Check for an infinite loop caused by a copy with offset==0
@ -1054,7 +957,10 @@ TEST(Snappy, ZeroOffsetCopyValidation) {
namespace {
int TestFindMatchLength(const char* s1, const char *s2, unsigned length) {
return snappy::internal::FindMatchLength(s1, s2, s2 + length);
std::pair<size_t, bool> p =
snappy::internal::FindMatchLength(s1, s2, s2 + length);
CHECK_EQ(p.first < 8, p.second);
return p.first;
}
} // namespace
@ -1150,22 +1056,24 @@ TEST(Snappy, FindMatchLength) {
}
TEST(Snappy, FindMatchLengthRandom) {
const int kNumTrials = 10000;
const int kTypicalLength = 10;
ACMRandom rnd(FLAGS_test_random_seed);
constexpr int kNumTrials = 10000;
constexpr int kTypicalLength = 10;
std::minstd_rand0 rng(FLAGS_test_random_seed);
std::uniform_int_distribution<int> uniform_byte(0, 255);
std::bernoulli_distribution one_in_two(1.0 / 2);
std::bernoulli_distribution one_in_typical_length(1.0 / kTypicalLength);
for (int i = 0; i < kNumTrials; i++) {
string s, t;
char a = rnd.Rand8();
char b = rnd.Rand8();
while (!rnd.OneIn(kTypicalLength)) {
s.push_back(rnd.OneIn(2) ? a : b);
t.push_back(rnd.OneIn(2) ? a : b);
std::string s, t;
char a = static_cast<char>(uniform_byte(rng));
char b = static_cast<char>(uniform_byte(rng));
while (!one_in_typical_length(rng)) {
s.push_back(one_in_two(rng) ? a : b);
t.push_back(one_in_two(rng) ? a : b);
}
DataEndingAtUnreadablePage u(s);
DataEndingAtUnreadablePage v(t);
int matched = snappy::internal::FindMatchLength(
u.data(), v.data(), v.data() + t.size());
int matched = TestFindMatchLength(u.data(), v.data(), t.size());
if (matched == t.size()) {
EXPECT_EQ(s, t);
} else {
@ -1195,7 +1103,6 @@ TEST(Snappy, VerifyCharTable) {
using snappy::internal::COPY_2_BYTE_OFFSET;
using snappy::internal::COPY_4_BYTE_OFFSET;
using snappy::internal::char_table;
using snappy::internal::wordmask;
uint16 dst[256];
@ -1272,49 +1179,46 @@ TEST(Snappy, VerifyCharTable) {
}
static void CompressFile(const char* fname) {
string fullinput;
std::string fullinput;
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
string compressed;
std::string compressed;
Compress(fullinput.data(), fullinput.size(), SNAPPY, &compressed, false);
CHECK_OK(file::SetContents(string(fname).append(".comp"), compressed,
CHECK_OK(file::SetContents(std::string(fname).append(".comp"), compressed,
file::Defaults()));
}
static void UncompressFile(const char* fname) {
string fullinput;
std::string fullinput;
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
size_t uncompLength;
CHECK(CheckUncompressedLength(fullinput, &uncompLength));
string uncompressed;
std::string uncompressed;
uncompressed.resize(uncompLength);
CHECK(snappy::Uncompress(fullinput.data(), fullinput.size(), &uncompressed));
CHECK_OK(file::SetContents(string(fname).append(".uncomp"), uncompressed,
CHECK_OK(file::SetContents(std::string(fname).append(".uncomp"), uncompressed,
file::Defaults()));
}
static void MeasureFile(const char* fname) {
string fullinput;
std::string fullinput;
CHECK_OK(file::GetContents(fname, &fullinput, file::Defaults()));
printf("%-40s :\n", fname);
int start_len = (FLAGS_start_len < 0) ? fullinput.size() : FLAGS_start_len;
int end_len = fullinput.size();
if (FLAGS_end_len >= 0) {
end_len = min<int>(fullinput.size(), FLAGS_end_len);
end_len = std::min<int>(fullinput.size(), FLAGS_end_len);
}
for (int len = start_len; len <= end_len; len++) {
const char* const input = fullinput.data();
int repeats = (FLAGS_bytes + len) / (len + 1);
if (FLAGS_zlib) Measure(input, len, ZLIB, repeats, 1024<<10);
if (FLAGS_lzo) Measure(input, len, LZO, repeats, 1024<<10);
if (FLAGS_liblzf) Measure(input, len, LIBLZF, repeats, 1024<<10);
if (FLAGS_quicklz) Measure(input, len, QUICKLZ, repeats, 1024<<10);
if (FLAGS_fastlz) Measure(input, len, FASTLZ, repeats, 1024<<10);
if (FLAGS_snappy) Measure(input, len, SNAPPY, repeats, 4096<<10);
// For block-size based measurements
@ -1354,10 +1258,10 @@ static void BM_UFlat(int iters, int arg) {
// Pick file to process based on "arg"
CHECK_GE(arg, 0);
CHECK_LT(arg, ARRAYSIZE(files));
string contents = ReadTestDataFile(files[arg].filename,
files[arg].size_limit);
std::string contents =
ReadTestDataFile(files[arg].filename, files[arg].size_limit);
string zcontents;
std::string zcontents;
snappy::Compress(contents.data(), contents.size(), &zcontents);
char* dst = new char[contents.size()];
@ -1380,10 +1284,10 @@ static void BM_UValidate(int iters, int arg) {
// Pick file to process based on "arg"
CHECK_GE(arg, 0);
CHECK_LT(arg, ARRAYSIZE(files));
string contents = ReadTestDataFile(files[arg].filename,
files[arg].size_limit);
std::string contents =
ReadTestDataFile(files[arg].filename, files[arg].size_limit);
string zcontents;
std::string zcontents;
snappy::Compress(contents.data(), contents.size(), &zcontents);
SetBenchmarkBytesProcessed(static_cast<int64>(iters) *
@ -1403,10 +1307,10 @@ static void BM_UIOVec(int iters, int arg) {
// Pick file to process based on "arg"
CHECK_GE(arg, 0);
CHECK_LT(arg, ARRAYSIZE(files));
string contents = ReadTestDataFile(files[arg].filename,
files[arg].size_limit);
std::string contents =
ReadTestDataFile(files[arg].filename, files[arg].size_limit);
string zcontents;
std::string zcontents;
snappy::Compress(contents.data(), contents.size(), &zcontents);
// Uncompress into an iovec containing ten entries.
@ -1449,10 +1353,10 @@ static void BM_UFlatSink(int iters, int arg) {
// Pick file to process based on "arg"
CHECK_GE(arg, 0);
CHECK_LT(arg, ARRAYSIZE(files));
string contents = ReadTestDataFile(files[arg].filename,
files[arg].size_limit);
std::string contents =
ReadTestDataFile(files[arg].filename, files[arg].size_limit);
string zcontents;
std::string zcontents;
snappy::Compress(contents.data(), contents.size(), &zcontents);
char* dst = new char[contents.size()];
@ -1467,7 +1371,7 @@ static void BM_UFlatSink(int iters, int arg) {
}
StopBenchmarkTiming();
string s(dst, contents.size());
std::string s(dst, contents.size());
CHECK_EQ(contents, s);
delete[] dst;
@ -1481,8 +1385,8 @@ static void BM_ZFlat(int iters, int arg) {
// Pick file to process based on "arg"
CHECK_GE(arg, 0);
CHECK_LT(arg, ARRAYSIZE(files));
string contents = ReadTestDataFile(files[arg].filename,
files[arg].size_limit);
std::string contents =
ReadTestDataFile(files[arg].filename, files[arg].size_limit);
char* dst = new char[snappy::MaxCompressedLength(contents.size())];
@ -1497,16 +1401,89 @@ static void BM_ZFlat(int iters, int arg) {
StopBenchmarkTiming();
const double compression_ratio =
static_cast<double>(zsize) / std::max<size_t>(1, contents.size());
SetBenchmarkLabel(StringPrintf("%s (%.2f %%)",
files[arg].label, 100.0 * compression_ratio));
VLOG(0) << StringPrintf("compression for %s: %zd -> %zd bytes",
files[arg].label, contents.size(), zsize);
SetBenchmarkLabel(StrFormat("%s (%.2f %%)", files[arg].label,
100.0 * compression_ratio));
VLOG(0) << StrFormat("compression for %s: %zd -> %zd bytes",
files[arg].label, static_cast<int>(contents.size()),
static_cast<int>(zsize));
delete[] dst;
}
BENCHMARK(BM_ZFlat)->DenseRange(0, ARRAYSIZE(files) - 1);
} // namespace snappy
static void BM_ZFlatAll(int iters, int arg) {
StopBenchmarkTiming();
CHECK_EQ(arg, 0);
const int num_files = ARRAYSIZE(files);
std::vector<std::string> contents(num_files);
std::vector<char*> dst(num_files);
int64 total_contents_size = 0;
for (int i = 0; i < num_files; ++i) {
contents[i] = ReadTestDataFile(files[i].filename, files[i].size_limit);
dst[i] = new char[snappy::MaxCompressedLength(contents[i].size())];
total_contents_size += contents[i].size();
}
SetBenchmarkBytesProcessed(static_cast<int64>(iters) * total_contents_size);
StartBenchmarkTiming();
size_t zsize = 0;
while (iters-- > 0) {
for (int i = 0; i < num_files; ++i) {
snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i],
&zsize);
}
}
StopBenchmarkTiming();
for (int i = 0; i < num_files; ++i) {
delete[] dst[i];
}
SetBenchmarkLabel(StrFormat("%d files", num_files));
}
BENCHMARK(BM_ZFlatAll)->DenseRange(0, 0);
static void BM_ZFlatIncreasingTableSize(int iters, int arg) {
StopBenchmarkTiming();
CHECK_EQ(arg, 0);
CHECK_GT(ARRAYSIZE(files), 0);
const std::string base_content =
ReadTestDataFile(files[0].filename, files[0].size_limit);
std::vector<std::string> contents;
std::vector<char*> dst;
int64 total_contents_size = 0;
for (int table_bits = kMinHashTableBits; table_bits <= kMaxHashTableBits;
++table_bits) {
std::string content = base_content;
content.resize(1 << table_bits);
dst.push_back(new char[snappy::MaxCompressedLength(content.size())]);
total_contents_size += content.size();
contents.push_back(std::move(content));
}
size_t zsize = 0;
SetBenchmarkBytesProcessed(static_cast<int64>(iters) * total_contents_size);
StartBenchmarkTiming();
while (iters-- > 0) {
for (int i = 0; i < contents.size(); ++i) {
snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i],
&zsize);
}
}
StopBenchmarkTiming();
for (int i = 0; i < dst.size(); ++i) {
delete[] dst[i];
}
SetBenchmarkLabel(StrFormat("%zd tables", contents.size()));
}
BENCHMARK(BM_ZFlatIncreasingTableSize)->DenseRange(0, 0);
} // namespace snappy
int main(int argc, char** argv) {
InitGoogle(argv[0], &argc, &argv, true);
@ -1515,11 +1492,11 @@ int main(int argc, char** argv) {
if (argc >= 2) {
for (int arg = 1; arg < argc; arg++) {
if (FLAGS_write_compressed) {
CompressFile(argv[arg]);
snappy::CompressFile(argv[arg]);
} else if (FLAGS_write_uncompressed) {
UncompressFile(argv[arg]);
snappy::UncompressFile(argv[arg]);
} else {
MeasureFile(argv[arg]);
snappy::MeasureFile(argv[arg]);
}
}
return 0;