Make the maximum input size for LLVMFuzzer targets configurable.

Replace the hardcoded maximum input size (4096) with a new flag, `--llvm_fuzzer_wrapper_max_input_size`, allowing users to specify a different limit for wrapped LLVMFuzzer targets.

PiperOrigin-RevId: 878511344
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index c3bd226..fe241cd 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -171,6 +171,7 @@
         "@com_google_fuzztest//common:logging",
         "@com_google_fuzztest//fuzztest/internal:io",
         "@com_google_fuzztest//fuzztest/internal/domains:core_domains_impl",
+        "@com_google_fuzztest//fuzztest/internal/domains:lazy",
     ],
     alwayslink = True,
 )
diff --git a/fuzztest/CMakeLists.txt b/fuzztest/CMakeLists.txt
index 960b6e2..ecaf619 100644
--- a/fuzztest/CMakeLists.txt
+++ b/fuzztest/CMakeLists.txt
@@ -235,4 +235,5 @@
     fuzztest::common_logging
     fuzztest::io
     fuzztest::core_domains_impl
+    fuzztest::lazy
 )
diff --git a/fuzztest/internal/domains/BUILD b/fuzztest/internal/domains/BUILD
index 8434788..58a6a81 100644
--- a/fuzztest/internal/domains/BUILD
+++ b/fuzztest/internal/domains/BUILD
@@ -235,3 +235,16 @@
     hdrs = ["utf.h"],
     deps = ["@abseil-cpp//absl/strings:string_view"],
 )
+
+cc_library(
+    name = "lazy",
+    hdrs = ["lazy.h"],
+    deps = [
+        ":core_domains_impl",
+        "@abseil-cpp//absl/random:bit_gen_ref",
+        "@abseil-cpp//absl/status",
+        "@com_google_fuzztest//common:logging",
+        "@com_google_fuzztest//fuzztest/internal:meta",
+        "@com_google_fuzztest//fuzztest/internal:serialization",
+    ],
+)
diff --git a/fuzztest/internal/domains/CMakeLists.txt b/fuzztest/internal/domains/CMakeLists.txt
index 6e27f15..3c1759b 100644
--- a/fuzztest/internal/domains/CMakeLists.txt
+++ b/fuzztest/internal/domains/CMakeLists.txt
@@ -224,3 +224,16 @@
   DEPS
     absl::string_view
 )
+fuzztest_cc_library(
+  NAME
+    lazy
+  HDRS
+    "lazy.h"
+  DEPS
+    fuzztest::core_domains_impl
+    absl::random_bit_gen_ref
+    absl::status
+    fuzztest::common_logging
+    fuzztest::meta
+    fuzztest::serialization
+)
diff --git a/fuzztest/internal/domains/lazy.h b/fuzztest/internal/domains/lazy.h
new file mode 100644
index 0000000..ff9fd7e
--- /dev/null
+++ b/fuzztest/internal/domains/lazy.h
@@ -0,0 +1,130 @@
+// Copyright 2026 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef FUZZTEST_FUZZTEST_INTERNAL_DOMAINS_LAZY_H_
+#define FUZZTEST_FUZZTEST_INTERNAL_DOMAINS_LAZY_H_
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <optional>
+#include <tuple>
+#include <utility>
+
+#include "absl/random/bit_gen_ref.h"
+#include "absl/status/status.h"
+#include "./common/logging.h"
+#include "./fuzztest/internal/domains/domain_base.h"
+#include "./fuzztest/internal/meta.h"
+#include "./fuzztest/internal/serialization.h"
+
+namespace fuzztest {
+namespace internal {
+
+// A helper domain that allows its inner domain to be lazily initialized.
+template <typename DomainT, typename... Args>
+class Lazy : public domain_implementor::DomainBase<Lazy<DomainT, Args...>,
+                                                   value_type_t<DomainT>,
+                                                   corpus_type_t<DomainT>> {
+ public:
+  using typename Lazy::DomainBase::corpus_type;
+  using typename Lazy::DomainBase::value_type;
+
+  Lazy(Args&&... args)
+      : args_(std::tuple<Args...>(std::forward<Args>(args)...)) {}
+
+  Lazy(const Lazy& other) {
+    if (other.inner_ != nullptr) {
+      inner_ = std::make_unique<DomainT>(*other.inner_);
+    } else {
+      args_ = other.args_;
+      setup_ = other.setup_;
+    }
+  }
+
+  Lazy(Lazy&& other) noexcept = default;
+  Lazy& operator=(Lazy&& other) = default;
+
+  corpus_type Init(absl::BitGenRef prng) { return GetInnerDomain().Init(prng); }
+
+  Lazy& WithLazySetup(std::function<void(DomainT&)> setup) {
+    setup_ = std::move(setup);
+    return *this;
+  }
+
+  void Mutate(corpus_type& corpus_value, absl::BitGenRef prng,
+              const domain_implementor::MutationMetadata& metadata,
+              bool only_shrink) {
+    GetInnerDomain().Mutate(corpus_value, prng, metadata, only_shrink);
+  }
+
+  value_type GetValue(const corpus_type& corpus_value) const {
+    return GetInnerDomain().GetValue(corpus_value);
+  }
+
+  std::optional<corpus_type> FromValue(const value_type& v) const {
+    return GetInnerDomain().FromValue(v);
+  }
+
+  std::optional<corpus_type> ParseCorpus(const IRObject& obj) const {
+    return GetInnerDomain().ParseCorpus(obj);
+  }
+
+  IRObject SerializeCorpus(const corpus_type& corpus_value) const {
+    return GetInnerDomain().SerializeCorpus(corpus_value);
+  }
+
+  absl::Status ValidateCorpusValue(const corpus_type& corpus_value) const {
+    return GetInnerDomain().ValidateCorpusValue(corpus_value);
+  }
+
+  auto GetPrinter() const { return GetInnerDomain().GetPrinter(); }
+
+ private:
+  template <std::size_t... Is>
+  void PopulateInner(std::index_sequence<Is...>) const {
+    FUZZTEST_CHECK(args_.has_value())
+        << "args is unavailable for creating the inner domain";
+    inner_ = std::make_unique<DomainT>(std::move(std::get<Is>(*args_))...);
+    if (setup_) setup_(*inner_);
+    args_ = std::nullopt;
+    setup_ = {};
+  }
+
+  const DomainT& GetInnerDomain() const {
+    if (inner_ == nullptr) {
+      PopulateInner(std::index_sequence_for<Args...>{});
+    }
+    return *inner_;
+  }
+
+  DomainT& GetInnerDomain() {
+    if (inner_ == nullptr) {
+      PopulateInner(std::index_sequence_for<Args...>{});
+    }
+    return *inner_;
+  }
+
+  mutable std::unique_ptr<DomainT> inner_ = nullptr;
+  // Arguments passed to the inner domain constructor. Set iff inner_ ==
+  // nullptr.
+  mutable std::optional<std::tuple<Args...>> args_;
+  // Must be the default value if inner_ != nullptr.
+  mutable std::function<void(DomainT&)> setup_;
+};
+
+}  // namespace internal
+}  // namespace fuzztest
+
+#endif  // FUZZTEST_FUZZTEST_INTERNAL_DOMAINS_LAZY_H_
diff --git a/fuzztest/llvm_fuzzer_main.cc b/fuzztest/llvm_fuzzer_main.cc
index a170236..f9b17c3 100644
--- a/fuzztest/llvm_fuzzer_main.cc
+++ b/fuzztest/llvm_fuzzer_main.cc
@@ -1,3 +1,4 @@
+#include <cstddef>
 #include <string>
 
 #include "gtest/gtest.h"
@@ -14,6 +15,9 @@
 ABSL_FLAG(std::string, llvm_fuzzer_wrapper_corpus_dir, "",
           "Path to seed corpus directory used by the wrapped legacy LLVMFuzzer "
           "target (https://llvm.org/docs/LibFuzzer.html#fuzz-target).");
+ABSL_FLAG(size_t, llvm_fuzzer_wrapper_max_input_size, 4096,
+          "Maximum input size for the wrapped legacy LLVMFuzzer target "
+          "(https://llvm.org/docs/LibFuzzer.html#fuzz-target).");
 
 int main(int argc, char** argv) {
   absl::ParseCommandLine(argc, argv);
diff --git a/fuzztest/llvm_fuzzer_wrapper.cc b/fuzztest/llvm_fuzzer_wrapper.cc
index 5340220..6407725 100644
--- a/fuzztest/llvm_fuzzer_wrapper.cc
+++ b/fuzztest/llvm_fuzzer_wrapper.cc
@@ -21,12 +21,12 @@
 #include "./fuzztest/internal/domains/arbitrary_impl.h"
 #include "./fuzztest/internal/domains/container_of_impl.h"
 #include "./fuzztest/internal/domains/domain_base.h"
+#include "./fuzztest/internal/domains/lazy.h"
 #include "./fuzztest/internal/io.h"
 
 ABSL_DECLARE_FLAG(std::string, llvm_fuzzer_wrapper_dict_file);
 ABSL_DECLARE_FLAG(std::string, llvm_fuzzer_wrapper_corpus_dir);
-
-constexpr static size_t kByteArrayMaxLen = 4096;
+ABSL_DECLARE_FLAG(size_t, llvm_fuzzer_wrapper_max_input_size);
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
 
@@ -56,7 +56,10 @@
   for (const fuzztest::internal::FilePathAndData& file : files) {
     out.push_back(
         {file.data.begin(),
-         file.data.begin() + std::min(file.data.size(), kByteArrayMaxLen)});
+         file.data.begin() +
+             std::min(
+                 file.data.size(),
+                 absl::GetFlag(FLAGS_llvm_fuzzer_wrapper_max_input_size))});
   }
   return out;
 }
@@ -177,16 +180,17 @@
  public:
   using typename Base::corpus_type;
 
-  ArbitraryByteVector() { WithMaxSize(kByteArrayMaxLen); }
+  ArbitraryByteVector() = default;
 
   void Mutate(corpus_type& val, absl::BitGenRef prng,
               const MutationMetadata& metadata, bool only_shrink) {
     if (LLVMFuzzerCustomMutator) {
       const size_t size = val.size();
-      const size_t max_size = only_shrink ? size : kByteArrayMaxLen;
-      val.resize(max_size);
+      const size_t mutant_max_size = only_shrink ? size : max_size();
+      val.resize(mutant_max_size);
       mutation_metadata_manager->Activate(metadata);
-      val.resize(LLVMFuzzerCustomMutator(val.data(), size, max_size, prng()));
+      val.resize(
+          LLVMFuzzerCustomMutator(val.data(), size, mutant_max_size, prng()));
       mutation_metadata_manager->Deactivate();
     } else {
       Base::Mutate(val, prng, metadata, only_shrink);
@@ -199,6 +203,9 @@
 }
 
 FUZZ_TEST(LLVMFuzzer, TestOneInput)
-    .WithDomains(ArbitraryByteVector()
-                     .WithDictionary(ReadByteArrayDictionaryFromFile)
-                     .WithSeeds(ReadByteArraysFromDirectory));
+    .WithDomains(fuzztest::internal::Lazy<ArbitraryByteVector>().WithLazySetup(
+        [](auto& d) {
+          d.WithMaxSize(absl::GetFlag(FLAGS_llvm_fuzzer_wrapper_max_input_size))
+              .WithDictionary(ReadByteArrayDictionaryFromFile)
+              .WithSeeds(ReadByteArraysFromDirectory);
+        }));