xref: /aosp_15_r20/external/pdfium/testing/fuzzers/pdf_jpx_fuzzer.cc (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2016 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cstdint>
6 #include <memory>
7 
8 #include "core/fpdfapi/page/cpdf_colorspace.h"
9 #include "core/fxcodec/jpx/cjpx_decoder.h"
10 #include "core/fxcrt/fx_safe_types.h"
11 #include "core/fxge/dib/cfx_dibitmap.h"
12 #include "core/fxge/dib/fx_dib.h"
13 
14 namespace {
15 
16 const uint32_t kMaxJPXFuzzSize = 100 * 1024 * 1024;  // 100 MB
17 
CheckImageSize(const CJPX_Decoder::JpxImageInfo & image_info)18 bool CheckImageSize(const CJPX_Decoder::JpxImageInfo& image_info) {
19   static constexpr uint32_t kMemLimitBytes = 1024 * 1024 * 1024;  // 1 GB.
20   FX_SAFE_UINT32 mem = image_info.width;
21   mem *= image_info.height;
22   mem *= image_info.channels;
23   return mem.IsValid() && mem.ValueOrDie() <= kMemLimitBytes;
24 }
25 
26 }  // namespace
27 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)28 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
29   if (size < 2)
30     return 0;
31 
32   std::unique_ptr<CJPX_Decoder> decoder = CJPX_Decoder::Create(
33       {data + 2, size - 2},
34       static_cast<CJPX_Decoder::ColorSpaceOption>(data[0] % 3), data[1]);
35   if (!decoder)
36     return 0;
37 
38   // A call to StartDecode could be too expensive if image size is very big, so
39   // check size before calling StartDecode().
40   CJPX_Decoder::JpxImageInfo image_info = decoder->GetInfo();
41   if (!CheckImageSize(image_info))
42     return 0;
43 
44   if (!decoder->StartDecode())
45     return 0;
46 
47   // StartDecode() could change image size, so check again.
48   image_info = decoder->GetInfo();
49   if (!CheckImageSize(image_info))
50     return 0;
51 
52   FXDIB_Format format;
53   if (image_info.channels == 1) {
54     format = FXDIB_Format::k8bppRgb;
55   } else if (image_info.channels <= 3) {
56     format = FXDIB_Format::kRgb;
57   } else if (image_info.channels == 4) {
58     format = FXDIB_Format::kRgb32;
59   } else {
60     image_info.width = (image_info.width * image_info.channels + 2) / 3;
61     format = FXDIB_Format::kRgb;
62   }
63   auto bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
64   if (!bitmap->Create(image_info.width, image_info.height, format))
65     return 0;
66 
67   if (bitmap->GetHeight() <= 0 ||
68       kMaxJPXFuzzSize / bitmap->GetPitch() <
69           static_cast<uint32_t>(bitmap->GetHeight()))
70     return 0;
71 
72   decoder->Decode(bitmap->GetWritableBuffer(), bitmap->GetPitch(),
73                   /*swap_rgb=*/false, GetCompsFromFormat(format));
74 
75   return 0;
76 }
77