libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

transforms_fuzzer.cc (5069B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include <stdint.h>
      7 
      8 #include "lib/jxl/base/random.h"
      9 #include "lib/jxl/base/status.h"
     10 #include "lib/jxl/dec_bit_reader.h"
     11 #include "lib/jxl/modular/encoding/encoding.h"
     12 #include "lib/jxl/modular/transform/transform.h"
     13 
     14 namespace jpegxl {
     15 namespace tools {
     16 
     17 using ::jxl::BitReader;
     18 using ::jxl::BitReaderScopedCloser;
     19 using ::jxl::Bytes;
     20 using ::jxl::Channel;
     21 using ::jxl::GroupHeader;
     22 using ::jxl::Image;
     23 using ::jxl::ModularOptions;
     24 using ::jxl::pixel_type;
     25 using ::jxl::Rng;
     26 using ::jxl::Status;
     27 using ::jxl::Transform;
     28 using ::jxl::weighted::Header;
     29 
     30 namespace {
     31 void FillChannel(Channel& ch, Rng& rng) {
     32   auto* p = &ch.plane;
     33   const size_t w = ch.w;
     34   const size_t h = ch.h;
     35   for (size_t y = 0; y < h; ++y) {
     36     pixel_type* row = p->Row(y);
     37     for (size_t x = 0; x < w; ++x) {
     38       row[x] = rng.UniformU(0, 0x80000000);
     39     }
     40   }
     41 }
     42 template <typename T>
     43 void AssertEq(T a, T b) {
     44   if (a != b) __builtin_trap();
     45 }
     46 }  // namespace
     47 
     48 int TestOneInput(const uint8_t* data, size_t size) {
     49   static Status nevermind = true;
     50   BitReader reader(Bytes(data, size));
     51   BitReaderScopedCloser reader_closer(&reader, &nevermind);
     52 
     53   Rng rng(reader.ReadFixedBits<56>());
     54 
     55   // One of {0, 1, _2_, 3}; "2" will be filtered out soon.
     56   size_t nb_chans = static_cast<size_t>(reader.ReadFixedBits<8>()) & 0x3;
     57   size_t nb_extra = static_cast<size_t>(reader.ReadFixedBits<8>()) & 0x7;
     58   // 1..32
     59   size_t bit_depth =
     60       (static_cast<size_t>(reader.ReadFixedBits<8>()) & 0x1F) + 1;
     61   // {0, 1, 2, 3}
     62   size_t log_upsampling =
     63       (static_cast<size_t>(reader.ReadFixedBits<8>()) & 0x3);
     64   size_t upsampling = 1 << log_upsampling;
     65 
     66   size_t w_orig = static_cast<size_t>(reader.ReadFixedBits<16>());
     67   size_t h_orig = static_cast<size_t>(reader.ReadFixedBits<16>());
     68   size_t w = jxl::DivCeil(w_orig, upsampling);
     69   size_t h = jxl::DivCeil(h_orig, upsampling);
     70 
     71   if ((nb_chans == 2) || ((nb_chans + nb_extra) == 0) || (w * h == 0) ||
     72       ((w_orig * h_orig * (nb_chans + nb_extra)) > (1 << 23))) {
     73     return 0;
     74   }
     75 
     76   std::vector<int> hshift;
     77   std::vector<int> vshift;
     78   std::vector<size_t> ec_upsampling;
     79 
     80   for (size_t c = 0; c < nb_chans; c++) {
     81     hshift.push_back(static_cast<int>(reader.ReadFixedBits<8>()) & 1);
     82     vshift.push_back(static_cast<int>(reader.ReadFixedBits<8>()) & 1);
     83   }
     84 
     85   for (size_t ec = 0; ec < nb_extra; ec++) {
     86     size_t log_ec_upsampling =
     87         (static_cast<size_t>(reader.ReadFixedBits<8>()) & 0x3);
     88     log_ec_upsampling = std::max(log_ec_upsampling, log_upsampling);
     89     ec_upsampling.push_back(1 << log_ec_upsampling);
     90   }
     91 
     92   JXL_ASSIGN_OR_DIE(Image image,
     93                     Image::Create(w, h, bit_depth, nb_chans + nb_extra));
     94 
     95   for (size_t c = 0; c < nb_chans; c++) {
     96     Channel& ch = image.channel[c];
     97     ch.hshift = hshift[c];
     98     ch.vshift = vshift[c];
     99     JXL_CHECK(ch.shrink(jxl::DivCeil(w, 1 << hshift[c]),
    100                         jxl::DivCeil(h, 1 << vshift[c])));
    101   }
    102 
    103   for (size_t ec = 0; ec < nb_extra; ec++) {
    104     Channel& ch = image.channel[ec + nb_chans];
    105     size_t ch_up = ec_upsampling[ec];
    106     int up_level =
    107         jxl::CeilLog2Nonzero(ch_up) - jxl::CeilLog2Nonzero(upsampling);
    108     JXL_CHECK(
    109         ch.shrink(jxl::DivCeil(w_orig, ch_up), jxl::DivCeil(h_orig, ch_up)));
    110     ch.hshift = ch.vshift = up_level;
    111   }
    112 
    113   GroupHeader header;
    114   if (!jxl::Bundle::Read(&reader, &header)) return 0;
    115   Header w_header;
    116   if (!jxl::Bundle::Read(&reader, &w_header)) return 0;
    117 
    118   // TODO(eustas): give it a try?
    119   if (!reader.AllReadsWithinBounds()) return 0;
    120 
    121   image.transform = header.transforms;
    122   for (Transform& transform : image.transform) {
    123     if (!transform.MetaApply(image)) return 0;
    124   }
    125   if (image.error) return 0;
    126 
    127   ModularOptions options;
    128   if (!ValidateChannelDimensions(image, options)) return 0;
    129 
    130   for (size_t i = 0; i < image.channel.size(); ++i) {
    131     FillChannel(image.channel[i], rng);
    132   }
    133 
    134   image.undo_transforms(w_header);
    135 
    136   AssertEq(image.error, false);
    137   AssertEq<size_t>(image.nb_meta_channels, 0);
    138   AssertEq(image.channel.size(), nb_chans + nb_extra);
    139 
    140   for (size_t c = 0; c < nb_chans; c++) {
    141     const Channel& ch = image.channel[c];
    142     AssertEq(ch.hshift, hshift[c]);
    143     AssertEq(ch.vshift, vshift[c]);
    144     AssertEq(ch.w, jxl::DivCeil(w, 1 << hshift[c]));
    145     AssertEq(ch.h, jxl::DivCeil(h, 1 << vshift[c]));
    146   }
    147 
    148   for (size_t ec = 0; ec < nb_extra; ec++) {
    149     const Channel& ch = image.channel[ec + nb_chans];
    150     size_t ch_up = ec_upsampling[ec];
    151     int up_level =
    152         jxl::CeilLog2Nonzero(ch_up) - jxl::CeilLog2Nonzero(upsampling);
    153     AssertEq(ch.w, jxl::DivCeil(w_orig, ch_up));
    154     AssertEq(ch.h, jxl::DivCeil(h_orig, ch_up));
    155     AssertEq(ch.hshift, up_level);
    156     AssertEq(ch.vshift, up_level);
    157   }
    158 
    159   return 0;
    160 }
    161 
    162 }  // namespace tools
    163 }  // namespace jpegxl
    164 
    165 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    166   return jpegxl::tools::TestOneInput(data, size);
    167 }