|  | // Copyright 2019 The PDFium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <fuzzer/FuzzedDataProvider.h> | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <vector> | 
|  |  | 
|  | #include "core/fpdfapi/page/cpdf_streamparser.h" | 
|  | #include "core/fpdfapi/parser/cpdf_dictionary.h" | 
|  | #include "core/fpdfapi/parser/cpdf_object.h" | 
|  | #include "core/fpdfdoc/cpdf_nametree.h" | 
|  | #include "third_party/base/span.h" | 
|  |  | 
|  | struct Params { | 
|  | bool delete_backwards; | 
|  | uint8_t count; | 
|  | std::vector<WideString> names; | 
|  | }; | 
|  |  | 
|  | std::vector<WideString> GetNames(uint8_t count, | 
|  | FuzzedDataProvider* data_provider) { | 
|  | std::vector<WideString> names; | 
|  | names.reserve(count); | 
|  | for (size_t i = 0; i < count; ++i) { | 
|  | // The name is not that interesting here. Keep it short. | 
|  | constexpr size_t kMaxNameLen = 10; | 
|  | std::string str = data_provider->ConsumeRandomLengthString(kMaxNameLen); | 
|  | names.push_back(WideString::FromUTF16LE( | 
|  | reinterpret_cast<const unsigned short*>(str.data()), | 
|  | str.size() / sizeof(unsigned short))); | 
|  | } | 
|  | return names; | 
|  | } | 
|  |  | 
|  | Params GetParams(FuzzedDataProvider* data_provider) { | 
|  | Params params; | 
|  | params.delete_backwards = data_provider->ConsumeBool(); | 
|  | params.count = data_provider->ConsumeIntegralInRange(1, 255); | 
|  | params.names = GetNames(params.count, data_provider); | 
|  | return params; | 
|  | } | 
|  |  | 
|  | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | 
|  | FuzzedDataProvider data_provider(data, size); | 
|  | Params params = GetParams(&data_provider); | 
|  |  | 
|  | // |remaining| needs to outlive |parser|. | 
|  | std::vector<uint8_t> remaining = | 
|  | data_provider.ConsumeRemainingBytes<uint8_t>(); | 
|  | if (remaining.empty()) | 
|  | return 0; | 
|  |  | 
|  | CPDF_StreamParser parser(remaining); | 
|  | auto dict = pdfium::MakeRetain<CPDF_Dictionary>(); | 
|  | std::unique_ptr<CPDF_NameTree> name_tree = | 
|  | CPDF_NameTree::CreateForTesting(dict.Get()); | 
|  | for (const auto& name : params.names) { | 
|  | RetainPtr<CPDF_Object> obj = parser.ReadNextObject( | 
|  | /*bAllowNestedArray*/ true, /*bInArray=*/false, /*dwRecursionLevel=*/0); | 
|  | if (!obj) | 
|  | break; | 
|  |  | 
|  | name_tree->AddValueAndName(std::move(obj), name); | 
|  | } | 
|  |  | 
|  | if (params.delete_backwards) { | 
|  | for (size_t i = params.count; i > 0; --i) | 
|  | name_tree->DeleteValueAndName(i); | 
|  | } else { | 
|  | for (size_t i = 0; i < params.count; ++i) | 
|  | name_tree->DeleteValueAndName(0); | 
|  | } | 
|  | return 0; | 
|  | } |