blob: c2eb56bdc526e07aeeb809996d48359fbb843133 [file] [log] [blame]
// Copyright 2021 The Chromium OS 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 <fcntl.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/files/scoped_file.h>
#include <base/files/scoped_temp_dir.h>
#include <base/message_loop/message_pump_type.h>
#include <base/posix/eintr_wrapper.h>
#include <base/run_loop.h>
#include <base/task/single_thread_task_executor.h>
#include <mojo/core/embedder/embedder.h>
#include <mojo/public/cpp/system/handle.h>
#include <mojo/public/cpp/bindings/pending_receiver.h>
#include <mojo/public/cpp/system/platform_handle.h>
#include <mojo/public/cpp/bindings/remote.h>
#include "ocr/mojo/ocr_service.mojom.h"
#include "ocr/ocr_service_impl.h"
namespace ocr {
namespace {
namespace mojo_ipc = chromeos::ocr::mojom;
// The relative path of the input test image.
constexpr char kTestImageRelativePath[] = "phototest.tif";
// The name of the output pdf file.
constexpr char kOutputPdfFilename[] = "phototest.pdf";
mojo::ScopedHandle GetInputFileHandle(const std::string& input_filename) {
base::ScopedFD input_fd(HANDLE_EINTR(
open(input_filename.c_str(), O_RDONLY | O_NOFOLLOW | O_NOCTTY)));
return mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(input_fd)));
}
mojo::ScopedHandle GetOutputFileHandle(const std::string& output_filename) {
base::ScopedFD out_fd(
HANDLE_EINTR(open(output_filename.c_str(), O_CREAT | O_WRONLY, 0644)));
return mojo::WrapPlatformHandle(mojo::PlatformHandle(std::move(out_fd)));
}
} // namespace
class OcrServiceFuzzer {
public:
OcrServiceFuzzer() {
logging::SetMinLogLevel(logging::LOG_FATAL);
mojo::core::Init();
ocr_service_impl_.AddReceiver(remote.BindNewPipeAndPassReceiver(),
false /* should_quit */);
}
public:
mojo::Remote<mojo_ipc::OpticalCharacterRecognitionService> remote;
private:
OcrServiceImpl ocr_service_impl_;
base::SingleThreadTaskExecutor executor_{base::MessagePumpType::IO};
};
// Tests OCR on a random input image generated by fuzzing data.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static OcrServiceFuzzer fuzzer_env;
// Write the fuzzer data to a file.
base::ScopedTempDir temp_dir_;
CHECK(temp_dir_.CreateUniqueTempDir());
base::FilePath file_path = temp_dir_.GetPath().Append(kTestImageRelativePath);
base::WriteFile(file_path, (const char*)data, size);
// Construct request.
const std::string input_image_filename = file_path.value();
mojo::ScopedHandle input_fd_handle = GetInputFileHandle(input_image_filename);
const std::string output_filename =
temp_dir_.GetPath().Append(kOutputPdfFilename).value();
mojo::ScopedHandle output_fd_handle = GetOutputFileHandle(output_filename);
mojo_ipc::OcrConfigPtr ocr_config = mojo_ipc::OcrConfig::New();
mojo_ipc::PdfRendererConfigPtr pdf_renderer_config =
mojo_ipc::PdfRendererConfig::New();
// Perform OCR.
bool ocr_callback_done = false;
fuzzer_env.remote->GenerateSearchablePdfFromImage(
std::move(input_fd_handle), std::move(output_fd_handle),
std::move(ocr_config), std::move(pdf_renderer_config),
base::BindOnce(
[](bool* ocr_callback_done,
const mojo_ipc::OpticalCharacterRecognitionServiceResponsePtr
response) { *ocr_callback_done = true; },
&ocr_callback_done));
base::RunLoop().RunUntilIdle();
return 0;
}
} // namespace ocr