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 --

Attachment: signature.asc
Description: PGP signature

Reply via email to