Control: retitle -1 snappy::Compress() with Source::Available() >= 2^32 returns empty Control: reassign -1 libsnappy1v5 Control: affects -1 src:snappy-tools Control: found -1 1.3.1-3 Control: found -1 1.3.1-1 Control: notfound -1 1.2.2-2+b2 Control: notfound -1 1.2.0-1
I repro this on sid, this is a regression in 1.3.1 against 1.2.
libsnappy snappy::Compress(), in 1.3.1-1 and onward,
treats files of size 2^32 bytes and larger, as empty:
ftruncate(source_file, 4 * 1024 * 1024 * 1024ull - 1); <- works
ftruncate(source_file, 4 * 1024 * 1024 * 1024ull); <- doesn't, empty
output
ftruncate(source_file, 4 * 1024 * 1024 * 1024ull + 1); <- doesn't, empty
output
# apt install ./*1.3*.deb
# c++ -O3 repro.cpp -orepro -lsnappy
# ltrace -Coll ./repro
size=4294967296 off=0; read=4294967296; available=4294967296
4G: 4294967296 -> 0 (0.00%)
# cat ll
open64("4G", 0x242, 0666)
= 3
ftruncate64(3, 4294967296)
= 0
close(1)
= 0
open64("4G.s", 0x241, 0666)
= 1
lseek64(3, 0, SEEK_END)
= 4294967296
fprintf(0x7f1cde2b14a0, "size=%ld off=%ld; read=%llu; ava"..., 4294967296, 0,
4294967296) = 61
snappy::Compress(snappy::Source*, snappy::Sink*)(0x7ffeee916750,
0x7ffeee916740, 0, 0) = 0
fprintf(0x7f1cde2b14a0, "%s: %llu -> %llu (%.2f%%)\n", "4G", 4294967296, 0,
0.000000) = 28
snappy::Source::~Source()(0x7ffeee916750, 0x7ffeee916590, 0, 0)
= 0x5575d8c55d58
snappy::Sink::~Sink()(0x7ffeee916740, 0x7ffeee916590, 0, 0)
= 0x5575d8c55d90
+++ exited (status 0) +++
# apt install ./*1.2.2*.deb
# ltrace -Coll ./repro
size=4294967296 off=0; read=4294967296; available=4294967296
4G: 4294967296 -> 201457665 (4.69%)
# head ll
open64("4G", 0x242, 0666)
= 3
ftruncate64(3, 4294967296)
= 0
close(1)
= 0
open64("4G.s", 0x241, 0666)
= 1
lseek64(3, 0, SEEK_END)
= 4294967296
fprintf(0x7f0af78084a0, "size=%ld off=%ld; read=%llu; ava"..., 4294967296, 0,
4294967296) = 61
snappy::Compress(snappy::Source*, snappy::Sink*)(0x7ffca4a5ec90,
0x7ffca4a5ec80, 0, 0 <unfinished ...>
fwrite("", 1, 1, 0x7f0af7808580)
= 1
pread64(3, "", 65536, 0)
= 65536
fwrite("", 1, 3074, 0x7f0af7808580)
= 3074
pread64(3, "", 65536, 65536)
= 65536
fwrite("", 1, 3074, 0x7f0af7808580)
= 3074
pread64(3, "", 65536, 131072)
= 65536
fwrite("", 1, 3074, 0x7f0af7808580)
= 3074
pread64(3, "", 65536, 196608)
= 65536
Reproducer:
-- >8 --
// SPDX-License-Identifier: 0BSD
#include <algorithm>
#include <atomic>
#include <clocale>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <err.h>
#include <fcntl.h>
#include <pthread.h>
#include <snappy-sinksource.h>
#include <snappy.h>
#include <unistd.h>
using namespace std::literals;
namespace {
static char buf[0xFFFFFF];
// A Source is an interface that yields a sequence of bytes
struct fd_source : snappy::Source {
int fd;
off_t size, off;
fd_source(int fd) : fd(fd), off(0) {
if((this->size = lseek(this->fd, 0, SEEK_END)) == -1)
this->off = -1;
}
// Return the number of bytes left to read from the source
virtual size_t Available() const { return this->size -
this->off; }
// Peek at the next flat region of the source. Does not
reposition
// the source. The returned region is empty iff Available()==0.
//
// Returns a pointer to the beginning of the region and store
its
// length in *len.
//
// The returned region is valid until the next call to Skip() or
// until this object is destroyed, whichever occurs first.
//
// The returned region may be larger than Available() (for
example
// if this ByteSource is a view on a substring of a larger
source).
// The caller is responsible for ensuring that it only reads the
// Available() bytes.
virtual const char * Peek(size_t * len) {
static_assert(snappy::kBlockSize <= sizeof(buf));
ssize_t rd;
while((rd = pread(this->fd, buf,
std::min(static_cast<off_t>(snappy::kBlockSize), this->size), this->off)) == -1
&& errno == EINTR)
;
if(rd == -1)
err(2, "%s", "4G");
if(rd == 0)
this->off = this->size;
*len = rd;
return buf;
}
// Skip the next n bytes. Invalidates any buffer returned by
// a previous call to Peek().
// REQUIRES: Available() >= n
virtual void Skip(size_t n) { this->off += n; }
};
struct FILE_sink : snappy::Sink {
FILE * f;
FILE_sink(FILE * f) : f(f) {}
// Append "bytes[0,n-1]" to this.
virtual void Append(const char * bytes, size_t n) {
if(std::fwrite(bytes, 1, n, this->f) != n)
err(2, "write error");
}
};
}
int main() {
int source_file = open("4G", O_RDWR | O_CREAT | O_TRUNC, 0666);
ftruncate(source_file, 4 * 1024 * 1024 * 1024ull);
close(1);
open("4G.s", O_WRONLY | O_CREAT | O_TRUNC, 0666);
FILE_sink sink{stdout};
fd_source source{source_file};
unsigned long long read = source.size - source.off;
std::fprintf(stderr, "size=%ld off=%ld; read=%llu; available=%zu\n",
source.size , source.off, read ,source.Available());
if(read != source.Available())
errno = EOVERFLOW, err(2, "%s", "4G");
unsigned long long written = Compress(&source, &sink);
std::fprintf(stderr, "%s: %llu -> %llu (%.2f%%)\n", "4G", read,
written, 100. * ((double)written / read));
}
-- >8 --
signature.asc
Description: PGP signature

