[poppler] 10 commits - cpp/tests glib/tests qt5/tests
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Fri Nov 27 13:12:39 UTC 2020
cpp/tests/CMakeLists.txt | 6
cpp/tests/fuzzing/FuzzedDataProvider.h | 409 ++++++++++++++++++++++++++++++++
cpp/tests/fuzzing/doc_fuzzer.cc | 49 +++
cpp/tests/fuzzing/fuzzer_temp_file.h | 82 ++++++
cpp/tests/fuzzing/page_label_fuzzer.cc | 41 +++
cpp/tests/fuzzing/page_search_fuzzer.cc | 33 +-
cpp/tests/fuzzing/pdf_file_fuzzer.cc | 37 ++
cpp/tests/fuzzing/pdf_fuzzer.cc | 37 ++
glib/tests/CMakeLists.txt | 18 +
glib/tests/fuzzing/annot_fuzzer.cc | 77 ++++++
glib/tests/fuzzing/doc_attr_fuzzer.cc | 33 ++
glib/tests/fuzzing/find_text_fuzzer.cc | 39 +++
glib/tests/fuzzing/fuzzer_temp_file.h | 82 ++++++
glib/tests/fuzzing/label_fuzzer.cc | 38 ++
glib/tests/fuzzing/pdf_draw_fuzzer.cc | 74 +++++
glib/tests/fuzzing/util_fuzzer.cc | 24 +
qt5/tests/CMakeLists.txt | 16 +
qt5/tests/fuzzing/qt_annot_fuzzer.cc | 46 +++
qt5/tests/fuzzing/qt_label_fuzzer.cc | 29 ++
qt5/tests/fuzzing/qt_pdf_fuzzer.cc | 27 ++
qt5/tests/fuzzing/qt_search_fuzzer.cc | 28 ++
qt5/tests/fuzzing/qt_textbox_fuzzer.cc | 32 ++
22 files changed, 1236 insertions(+), 21 deletions(-)
New commits:
commit 8ea1bf3c1069530171493a6b2dd49ac1f20120fc
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Thu Nov 26 15:59:51 2020 +0000
Replace malloc with calloc
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.cc b/glib/tests/fuzzing/doc_attr_fuzzer.cc
index 55924154..18d3811f 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.cc
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.cc
@@ -17,7 +17,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0;
}
- buf = (char *)malloc(size + 1);
+ buf = (char *)calloc(size + 1, sizeof(char));
memcpy(buf, data, size);
buf[size] = '\0';
diff --git a/glib/tests/fuzzing/find_text_fuzzer.cc b/glib/tests/fuzzing/find_text_fuzzer.cc
index 2e84ac78..e7d0ba90 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.cc
+++ b/glib/tests/fuzzing/find_text_fuzzer.cc
@@ -22,7 +22,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0;
}
- buf = (char *)malloc(size + 1);
+ buf = (char *)calloc(size + 1, sizeof(char));
memcpy(buf, data, size);
buf[size] = '\0';
diff --git a/glib/tests/fuzzing/label_fuzzer.cc b/glib/tests/fuzzing/label_fuzzer.cc
index a1ecfbd6..825a57aa 100644
--- a/glib/tests/fuzzing/label_fuzzer.cc
+++ b/glib/tests/fuzzing/label_fuzzer.cc
@@ -22,7 +22,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0;
}
- buf = (char *)malloc(size + 1);
+ buf = (char *)calloc(size + 1, sizeof(char));
memcpy(buf, data, size);
buf[size] = '\0';
diff --git a/glib/tests/fuzzing/util_fuzzer.cc b/glib/tests/fuzzing/util_fuzzer.cc
index a4c63252..6b6b10c3 100644
--- a/glib/tests/fuzzing/util_fuzzer.cc
+++ b/glib/tests/fuzzing/util_fuzzer.cc
@@ -10,7 +10,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
gsize length;
guint8 *tmp_uint;
- buf = (char *)malloc(size + 1);
+ buf = (char *)calloc(size + 1, sizeof(char));
memcpy(buf, data, size);
buf[size] = '\0';
commit e05e627a5f6e92cf1c1897c490851db176eb9999
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Mon Nov 9 11:31:58 2020 +0000
Clang format
diff --git a/glib/tests/fuzzing/annot_fuzzer.cc b/glib/tests/fuzzing/annot_fuzzer.cc
index f06d8d30..d36da68e 100644
--- a/glib/tests/fuzzing/annot_fuzzer.cc
+++ b/glib/tests/fuzzing/annot_fuzzer.cc
@@ -20,7 +20,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
cairo_surface_t *surface;
cairo_status_t status;
- doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char *)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.cc b/glib/tests/fuzzing/doc_attr_fuzzer.cc
index c5816ea9..55924154 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.cc
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.cc
@@ -11,7 +11,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages, n;
- doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char *)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/find_text_fuzzer.cc b/glib/tests/fuzzing/find_text_fuzzer.cc
index 4567e26e..2e84ac78 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.cc
+++ b/glib/tests/fuzzing/find_text_fuzzer.cc
@@ -11,7 +11,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages;
- doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char *)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/label_fuzzer.cc b/glib/tests/fuzzing/label_fuzzer.cc
index b5b2374c..a1ecfbd6 100644
--- a/glib/tests/fuzzing/label_fuzzer.cc
+++ b/glib/tests/fuzzing/label_fuzzer.cc
@@ -11,7 +11,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages;
- doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char *)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/pdf_draw_fuzzer.cc b/glib/tests/fuzzing/pdf_draw_fuzzer.cc
index 81277ee4..357fbf20 100644
--- a/glib/tests/fuzzing/pdf_draw_fuzzer.cc
+++ b/glib/tests/fuzzing/pdf_draw_fuzzer.cc
@@ -19,7 +19,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
cairo_surface_t *surface;
cairo_status_t status;
- doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char *)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/util_fuzzer.cc b/glib/tests/fuzzing/util_fuzzer.cc
index b39a1b30..a4c63252 100644
--- a/glib/tests/fuzzing/util_fuzzer.cc
+++ b/glib/tests/fuzzing/util_fuzzer.cc
@@ -14,7 +14,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
memcpy(buf, data, size);
buf[size] = '\0';
- tmp_ch = poppler_named_dest_from_bytestring((const guint8*)buf, size);
+ tmp_ch = poppler_named_dest_from_bytestring((const guint8 *)buf, size);
tmp_uint = poppler_named_dest_to_bytestring(buf, &length);
g_free(tmp_ch);
commit e09a603e2ff08ce50fc5a71146101bb4ce40c467
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Wed Nov 4 13:24:26 2020 +0000
Changing glib fuzzers from C to CPP
...
replace c with cc - glib
missing includes
diff --git a/glib/tests/CMakeLists.txt b/glib/tests/CMakeLists.txt
index 12f933b6..a2259cbe 100644
--- a/glib/tests/CMakeLists.txt
+++ b/glib/tests/CMakeLists.txt
@@ -63,10 +63,10 @@ macro(GLIB_ADD_FUZZER exe)
endmacro(GLIB_ADD_FUZZER)
if(ENABLE_FUZZER)
- glib_add_fuzzer(annot_fuzzer ./fuzzing/annot_fuzzer.c)
- glib_add_fuzzer(doc_attr_fuzzer ./fuzzing/doc_attr_fuzzer.c)
- glib_add_fuzzer(find_text_fuzzer ./fuzzing/find_text_fuzzer.c)
- glib_add_fuzzer(util_fuzzer ./fuzzing/util_fuzzer.c)
- glib_add_fuzzer(label_fuzzer ./fuzzing/label_fuzzer.c)
- glib_add_fuzzer(pdf_draw_fuzzer ./fuzzing/pdf_draw_fuzzer.c)
+ glib_add_fuzzer(annot_fuzzer ./fuzzing/annot_fuzzer.cc)
+ glib_add_fuzzer(doc_attr_fuzzer ./fuzzing/doc_attr_fuzzer.cc)
+ glib_add_fuzzer(find_text_fuzzer ./fuzzing/find_text_fuzzer.cc)
+ glib_add_fuzzer(util_fuzzer ./fuzzing/util_fuzzer.cc)
+ glib_add_fuzzer(label_fuzzer ./fuzzing/label_fuzzer.cc)
+ glib_add_fuzzer(pdf_draw_fuzzer ./fuzzing/pdf_draw_fuzzer.cc)
endif()
diff --git a/glib/tests/fuzzing/annot_fuzzer.c b/glib/tests/fuzzing/annot_fuzzer.cc
similarity index 92%
rename from glib/tests/fuzzing/annot_fuzzer.c
rename to glib/tests/fuzzing/annot_fuzzer.cc
index db9c033b..f06d8d30 100644
--- a/glib/tests/fuzzing/annot_fuzzer.c
+++ b/glib/tests/fuzzing/annot_fuzzer.cc
@@ -5,7 +5,7 @@
#include "fuzzer_temp_file.h"
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
GError *err = NULL;
PopplerDocument *doc;
@@ -20,7 +20,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
cairo_surface_t *surface;
cairo_status_t status;
- doc = poppler_document_new_from_data(data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.c b/glib/tests/fuzzing/doc_attr_fuzzer.cc
similarity index 76%
rename from glib/tests/fuzzing/doc_attr_fuzzer.c
rename to glib/tests/fuzzing/doc_attr_fuzzer.cc
index a20726aa..c5816ea9 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.c
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.cc
@@ -1,7 +1,9 @@
+#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
GError *err = NULL;
PopplerDocument *doc;
@@ -9,7 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages, n;
- doc = poppler_document_new_from_data(data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/find_text_fuzzer.c b/glib/tests/fuzzing/find_text_fuzzer.cc
similarity index 78%
rename from glib/tests/fuzzing/find_text_fuzzer.c
rename to glib/tests/fuzzing/find_text_fuzzer.cc
index 57707188..4567e26e 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.c
+++ b/glib/tests/fuzzing/find_text_fuzzer.cc
@@ -1,7 +1,9 @@
+#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
GError *err = NULL;
PopplerDocument *doc;
@@ -9,7 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages;
- doc = poppler_document_new_from_data(data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.cc
similarity index 77%
rename from glib/tests/fuzzing/label_fuzzer.c
rename to glib/tests/fuzzing/label_fuzzer.cc
index 87bfc6c8..b5b2374c 100644
--- a/glib/tests/fuzzing/label_fuzzer.c
+++ b/glib/tests/fuzzing/label_fuzzer.cc
@@ -1,7 +1,9 @@
+#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
GError *err = NULL;
PopplerDocument *doc;
@@ -9,7 +11,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
char *buf;
int npages;
- doc = poppler_document_new_from_data(data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/pdf_draw_fuzzer.c b/glib/tests/fuzzing/pdf_draw_fuzzer.cc
similarity index 92%
rename from glib/tests/fuzzing/pdf_draw_fuzzer.c
rename to glib/tests/fuzzing/pdf_draw_fuzzer.cc
index fffbdb20..81277ee4 100644
--- a/glib/tests/fuzzing/pdf_draw_fuzzer.c
+++ b/glib/tests/fuzzing/pdf_draw_fuzzer.cc
@@ -5,7 +5,7 @@
#include "fuzzer_temp_file.h"
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
GError *err = NULL;
PopplerDocument *doc;
@@ -19,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
cairo_surface_t *surface;
cairo_status_t status;
- doc = poppler_document_new_from_data(data, size, NULL, &err);
+ doc = poppler_document_new_from_data((char*)data, size, NULL, &err);
if (doc == NULL) {
g_error_free(err);
return 0;
diff --git a/glib/tests/fuzzing/util_fuzzer.c b/glib/tests/fuzzing/util_fuzzer.cc
similarity index 64%
rename from glib/tests/fuzzing/util_fuzzer.c
rename to glib/tests/fuzzing/util_fuzzer.cc
index 185a341f..b39a1b30 100644
--- a/glib/tests/fuzzing/util_fuzzer.c
+++ b/glib/tests/fuzzing/util_fuzzer.cc
@@ -1,7 +1,9 @@
+#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
char *tmp_ch;
char *buf;
@@ -12,7 +14,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
memcpy(buf, data, size);
buf[size] = '\0';
- tmp_ch = poppler_named_dest_from_bytestring(buf, size);
+ tmp_ch = poppler_named_dest_from_bytestring((const guint8*)buf, size);
tmp_uint = poppler_named_dest_to_bytestring(buf, &length);
g_free(tmp_ch);
commit 44af15369a974b2b26a10fa3f4f99ba8e7542bd9
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Fri Oct 30 00:41:41 2020 +0000
Fixing null-terminated string parameters
diff --git a/cpp/tests/fuzzing/doc_fuzzer.cc b/cpp/tests/fuzzing/doc_fuzzer.cc
index 520649c7..1769ce40 100644
--- a/cpp/tests/fuzzing/doc_fuzzer.cc
+++ b/cpp/tests/fuzzing/doc_fuzzer.cc
@@ -1,16 +1,19 @@
#include <cstdint>
-#include <poppler-global.h>
#include <poppler-document.h>
-#include <poppler-page.h>
+#include <poppler-global.h>
#include "FuzzedDataProvider.h"
const size_t input_size = 32;
+const size_t count = 6;
static void dummy_error_function(const std::string &, void *) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
+ if (size < input_size * count) {
+ return 0;
+ }
poppler::set_debug_error_function(dummy_error_function, nullptr);
poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
if (!doc || doc->is_locked()) {
@@ -34,12 +37,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
doc->set_subject(poppler::ustring::from_latin1(in_sub));
doc->set_title(poppler::ustring::from_latin1(in_title));
- doc->set_author(poppler::ustring::from_utf8((const char *)data, size));
- doc->set_creator(poppler::ustring::from_utf8((const char *)data, size));
- doc->set_keywords(poppler::ustring::from_utf8((const char *)data, size));
- doc->set_producer(poppler::ustring::from_utf8((const char *)data, size));
- doc->set_subject(poppler::ustring::from_utf8((const char *)data, size));
- doc->set_title(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_author(poppler::ustring::from_utf8(in_auth.c_str(), -1));
+ doc->set_creator(poppler::ustring::from_utf8(in_creat.c_str(), -1));
+ doc->set_keywords(poppler::ustring::from_utf8(in_key.c_str(), -1));
+ doc->set_producer(poppler::ustring::from_utf8(in_prod.c_str(), -1));
+ doc->set_subject(poppler::ustring::from_utf8(in_sub.c_str(), -1));
+ doc->set_title(poppler::ustring::from_utf8(in_title.c_str(), -1));
delete doc;
return 0;
diff --git a/cpp/tests/fuzzing/page_label_fuzzer.cc b/cpp/tests/fuzzing/page_label_fuzzer.cc
index 19106036..467be74a 100644
--- a/cpp/tests/fuzzing/page_label_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_label_fuzzer.cc
@@ -1,14 +1,20 @@
#include <cstdint>
-
-#include <poppler-global.h>
#include <poppler-document.h>
+#include <poppler-global.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
+#include "FuzzedDataProvider.h"
+
+const size_t input_size = 32;
+
static void dummy_error_function(const std::string &, void *) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
+ if (size < input_size) {
+ return 0;
+ }
poppler::set_debug_error_function(dummy_error_function, nullptr);
poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
@@ -18,13 +24,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
}
poppler::page_renderer r;
+ FuzzedDataProvider data_provider(data, size);
+ std::string in_label = data_provider.ConsumeBytesAsString(input_size);
for (int i = 0; i < doc->pages(); i++) {
- poppler::ustring label = poppler::ustring::from_utf8((const char *)data, size);
- poppler::page *p = doc->create_page(label);
+ poppler::page *p = doc->create_page(poppler::ustring::from_utf8(in_label.c_str(), -1));
if (!p) {
continue;
}
r.render_page(p);
+ p->label();
delete p;
}
diff --git a/cpp/tests/fuzzing/page_search_fuzzer.cc b/cpp/tests/fuzzing/page_search_fuzzer.cc
index 6427976c..1c6977f2 100644
--- a/cpp/tests/fuzzing/page_search_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_search_fuzzer.cc
@@ -1,14 +1,20 @@
#include <cstdint>
-
-#include <poppler-global.h>
#include <poppler-document.h>
+#include <poppler-global.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
+#include "FuzzedDataProvider.h"
+
+const size_t input_size = 32;
+
static void dummy_error_function(const std::string &, void *) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
+ if (size < input_size) {
+ return 0;
+ }
poppler::set_debug_error_function(dummy_error_function, nullptr);
poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
@@ -18,13 +24,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
}
poppler::page_renderer r;
+ FuzzedDataProvider data_provider(data, size);
+ std::string in_text = data_provider.ConsumeBytesAsString(input_size);
for (int i = 0; i < doc->pages(); i++) {
poppler::page *p = doc->create_page(i);
if (!p) {
continue;
}
poppler::rectf rect = p->page_rect();
- poppler::ustring text = poppler::ustring::from_utf8((const char *)data, size);
+ poppler::ustring text = poppler::ustring::from_utf8(in_text.c_str(), -1);
p->search(text, rect, poppler::page::search_from_top, poppler::case_insensitive, poppler::rotate_0);
r.render_page(p);
delete p;
diff --git a/cpp/tests/fuzzing/pdf_file_fuzzer.cc b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
index 6a682a17..10374e8b 100644
--- a/cpp/tests/fuzzing/pdf_file_fuzzer.cc
+++ b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
@@ -1,8 +1,6 @@
#include <cstdint>
-#include <string>
-
-#include <poppler-global.h>
#include <poppler-document.h>
+#include <poppler-global.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
diff --git a/cpp/tests/fuzzing/pdf_fuzzer.cc b/cpp/tests/fuzzing/pdf_fuzzer.cc
index 71cc9ae6..90cad426 100644
--- a/cpp/tests/fuzzing/pdf_fuzzer.cc
+++ b/cpp/tests/fuzzing/pdf_fuzzer.cc
@@ -1,34 +1,15 @@
-/*
-# Copyright 2018 Google Inc.
-#
-# 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.
-#
-################################################################################
-*/
-
#include <cstdint>
-
#include <poppler-destination.h>
-#include <poppler-global.h>
#include <poppler-document.h>
+#include <poppler-global.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
-static void nop_func(const std::string &msg, void *) {};
+static void dummy_error_function(const std::string &, void *) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
- poppler::set_debug_error_function(nop_func, nullptr);
+ poppler::set_debug_error_function(dummy_error_function, nullptr);
poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
if (!doc || doc->is_locked()) {
diff --git a/glib/tests/fuzzing/find_text_fuzzer.c b/glib/tests/fuzzing/find_text_fuzzer.c
index 744f0051..57707188 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.c
+++ b/glib/tests/fuzzing/find_text_fuzzer.c
@@ -6,6 +6,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
+ char *buf;
int npages;
doc = poppler_document_new_from_data(data, size, NULL, &err);
@@ -19,13 +20,18 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0;
}
+ buf = (char *)malloc(size + 1);
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
for (int n = 0; n < npages; n++) {
page = poppler_document_get_page(doc, n);
if (!page) {
continue;
}
- poppler_page_find_text(page, data);
+ poppler_page_find_text(page, buf);
g_object_unref(page);
}
+ free(buf);
return 0;
}
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.c
index 0cb5f6d4..87bfc6c8 100644
--- a/glib/tests/fuzzing/label_fuzzer.c
+++ b/glib/tests/fuzzing/label_fuzzer.c
@@ -23,8 +23,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
buf = (char *)malloc(size + 1);
memcpy(buf, data, size);
buf[size] = '\0';
+
for (int n = 0; n < npages; n++) {
- /*page = poppler_document_get_page_by_label(doc, data);*/
page = poppler_document_get_page_by_label(doc, buf);
if (!page) {
continue;
commit 919a71e52110774f461cbe079a5ed65cf8f48c91
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Thu Oct 29 23:32:15 2020 +0000
Updating pdf_fuzzer with the version from OSS-Fuzz repository
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index 18b17334..10ac0b32 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -22,6 +22,7 @@ cpp_add_simpletest(poppler-render poppler-render.cpp ${CMAKE_SOURCE_DIR}/utils/p
if(ENABLE_FUZZER)
cpp_add_simpletest(doc_fuzzer ./fuzzing/doc_fuzzer.cc)
+ cpp_add_simpletest(pdf_fuzzer ./fuzzing/pdf_fuzzer.cc)
cpp_add_simpletest(pdf_file_fuzzer ./fuzzing/pdf_file_fuzzer.cc)
cpp_add_simpletest(page_label_fuzzer ./fuzzing/page_label_fuzzer.cc)
cpp_add_simpletest(page_search_fuzzer ./fuzzing/page_search_fuzzer.cc)
diff --git a/cpp/tests/pdf_fuzzer.cc b/cpp/tests/fuzzing/pdf_fuzzer.cc
similarity index 80%
rename from cpp/tests/pdf_fuzzer.cc
rename to cpp/tests/fuzzing/pdf_fuzzer.cc
index 6924bc00..71cc9ae6 100644
--- a/cpp/tests/pdf_fuzzer.cc
+++ b/cpp/tests/fuzzing/pdf_fuzzer.cc
@@ -18,22 +18,27 @@
#include <cstdint>
+#include <poppler-destination.h>
#include <poppler-global.h>
#include <poppler-document.h>
#include <poppler-page.h>
#include <poppler-page-renderer.h>
-static void dummy_error_function(const std::string &, void *) { }
+static void nop_func(const std::string &msg, void *) {};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
- poppler::set_debug_error_function(dummy_error_function, nullptr);
+ poppler::set_debug_error_function(nop_func, nullptr);
poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
if (!doc || doc->is_locked()) {
delete doc;
return 0;
}
+ doc->metadata();
+ doc->create_destination_map();
+ doc->embedded_files();
+ doc->fonts();
poppler::page_renderer r;
for (int i = 0; i < doc->pages(); i++) {
@@ -42,6 +47,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
continue;
}
r.render_page(p);
+ p->text_list(poppler::page::text_list_include_font);
delete p;
}
commit 1e73805f7d8d1ca453550d133d86f59305011e78
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Wed Oct 28 01:00:58 2020 +0000
Fixes from Michael's feedback
diff --git a/cpp/tests/fuzzing/doc_fuzzer.cc b/cpp/tests/fuzzing/doc_fuzzer.cc
index b8dd957f..520649c7 100644
--- a/cpp/tests/fuzzing/doc_fuzzer.cc
+++ b/cpp/tests/fuzzing/doc_fuzzer.cc
@@ -1,11 +1,11 @@
#include <cstdint>
-
#include <poppler-global.h>
#include <poppler-document.h>
#include <poppler-page.h>
+
#include "FuzzedDataProvider.h"
-#define INPUT_SIZE 32
+const size_t input_size = 32;
static void dummy_error_function(const std::string &, void *) { }
@@ -19,12 +19,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
}
FuzzedDataProvider data_provider(data, size);
- std::string in_auth = data_provider.ConsumeBytesAsString(INPUT_SIZE);
- std::string in_creat = data_provider.ConsumeBytesAsString(INPUT_SIZE);
- std::string in_key = data_provider.ConsumeBytesAsString(INPUT_SIZE);
- std::string in_prod = data_provider.ConsumeBytesAsString(INPUT_SIZE);
- std::string in_sub = data_provider.ConsumeBytesAsString(INPUT_SIZE);
- std::string in_title = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_auth = data_provider.ConsumeBytesAsString(input_size);
+ std::string in_creat = data_provider.ConsumeBytesAsString(input_size);
+ std::string in_key = data_provider.ConsumeBytesAsString(input_size);
+ std::string in_prod = data_provider.ConsumeBytesAsString(input_size);
+ std::string in_sub = data_provider.ConsumeBytesAsString(input_size);
+ std::string in_title = data_provider.ConsumeBytesAsString(input_size);
// Testing both methods for conversion to ustring
doc->set_author(poppler::ustring::from_latin1(in_auth));
diff --git a/glib/tests/fuzzing/annot_fuzzer.c b/glib/tests/fuzzing/annot_fuzzer.c
index db3f0e49..db9c033b 100644
--- a/glib/tests/fuzzing/annot_fuzzer.c
+++ b/glib/tests/fuzzing/annot_fuzzer.c
@@ -56,8 +56,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
continue;
}
poppler_page_add_annot(page, annot);
- /*poppler_annot_set_contents(annot, data);*/
- /*poppler_annot_markup_set_label(annot, data);*/
}
cr = cairo_create(surface);
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.c b/glib/tests/fuzzing/doc_attr_fuzzer.c
index 1b62884b..a20726aa 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.c
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.c
@@ -6,6 +6,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
+ char *buf;
int npages, n;
doc = poppler_document_new_from_data(data, size, NULL, &err);
@@ -13,11 +14,18 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
g_error_free(err);
return 0;
}
- poppler_document_set_author(doc, data);
- poppler_document_set_creator(doc, data);
- poppler_document_set_keywords(doc, data);
- poppler_document_set_producer(doc, data);
- poppler_document_set_subject(doc, data);
- poppler_document_set_title(doc, data);
+
+ buf = (char *)malloc(size + 1);
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
+ poppler_document_set_author(doc, buf);
+ poppler_document_set_creator(doc, buf);
+ poppler_document_set_keywords(doc, buf);
+ poppler_document_set_producer(doc, buf);
+ poppler_document_set_subject(doc, buf);
+ poppler_document_set_title(doc, buf);
+
+ free(buf);
return 0;
}
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.c
index 5475184e..0cb5f6d4 100644
--- a/glib/tests/fuzzing/label_fuzzer.c
+++ b/glib/tests/fuzzing/label_fuzzer.c
@@ -6,6 +6,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
+ char *buf;
int npages;
doc = poppler_document_new_from_data(data, size, NULL, &err);
@@ -19,12 +20,17 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
return 0;
}
+ buf = (char *)malloc(size + 1);
+ memcpy(buf, data, size);
+ buf[size] = '\0';
for (int n = 0; n < npages; n++) {
- page = poppler_document_get_page_by_label(doc, data);
+ /*page = poppler_document_get_page_by_label(doc, data);*/
+ page = poppler_document_get_page_by_label(doc, buf);
if (!page) {
continue;
}
g_object_unref(page);
}
+ free(buf);
return 0;
}
diff --git a/glib/tests/fuzzing/util_fuzzer.c b/glib/tests/fuzzing/util_fuzzer.c
index 01f3c2d4..185a341f 100644
--- a/glib/tests/fuzzing/util_fuzzer.c
+++ b/glib/tests/fuzzing/util_fuzzer.c
@@ -3,8 +3,20 @@
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
+ char *tmp_ch;
+ char *buf;
gsize length;
- poppler_named_dest_from_bytestring(data, size);
- poppler_named_dest_to_bytestring(data, &length);
+ guint8 *tmp_uint;
+
+ buf = (char *)malloc(size + 1);
+ memcpy(buf, data, size);
+ buf[size] = '\0';
+
+ tmp_ch = poppler_named_dest_from_bytestring(buf, size);
+ tmp_uint = poppler_named_dest_to_bytestring(buf, &length);
+
+ g_free(tmp_ch);
+ g_free(tmp_uint);
+ free(buf);
return 0;
}
diff --git a/qt5/tests/fuzzing/FuzzedDataProvider.h b/qt5/tests/fuzzing/FuzzedDataProvider.h
deleted file mode 100644
index 1996bcad..00000000
--- a/qt5/tests/fuzzing/FuzzedDataProvider.h
+++ /dev/null
@@ -1,409 +0,0 @@
-//===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// A single header library providing an utility class to break up an array of
-// bytes. Whenever run on the same input, provides the same output, as long as
-// its methods are called in the same order, with the same arguments.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
-#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
-
-#include <algorithm>
-#include <climits>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <initializer_list>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
-
-// In addition to the comments below, the API is also briefly documented at
-// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
-class FuzzedDataProvider
-{
-public:
- // |data| is an array of length |size| that the FuzzedDataProvider wraps to
- // provide more granular access. |data| must outlive the FuzzedDataProvider.
- FuzzedDataProvider(const uint8_t *data, size_t size) : data_ptr_(data), remaining_bytes_(size) { }
- ~FuzzedDataProvider() = default;
-
- // See the implementation below (after the class definition) for more verbose
- // comments for each of the methods.
-
- // Methods returning std::vector of bytes. These are the most popular choice
- // when splitting fuzzing input into pieces, as every piece is put into a
- // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
- // will be released automatically.
- template<typename T>
- std::vector<T> ConsumeBytes(size_t num_bytes);
- template<typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
- template<typename T>
- std::vector<T> ConsumeRemainingBytes();
-
- // Methods returning strings. Use only when you need a std::string or a null
- // terminated C-string. Otherwise, prefer the methods returning std::vector.
- std::string ConsumeBytesAsString(size_t num_bytes);
- std::string ConsumeRandomLengthString(size_t max_length);
- std::string ConsumeRandomLengthString();
- std::string ConsumeRemainingBytesAsString();
-
- // Methods returning integer values.
- template<typename T>
- T ConsumeIntegral();
- template<typename T>
- T ConsumeIntegralInRange(T min, T max);
-
- // Methods returning floating point values.
- template<typename T>
- T ConsumeFloatingPoint();
- template<typename T>
- T ConsumeFloatingPointInRange(T min, T max);
-
- // 0 <= return value <= 1.
- template<typename T>
- T ConsumeProbability();
-
- bool ConsumeBool();
-
- // Returns a value chosen from the given enum.
- template<typename T>
- T ConsumeEnum();
-
- // Returns a value from the given array.
- template<typename T, size_t size>
- T PickValueInArray(const T (&array)[size]);
- template<typename T>
- T PickValueInArray(std::initializer_list<const T> list);
-
- // Writes data to the given destination and returns number of bytes written.
- size_t ConsumeData(void *destination, size_t num_bytes);
-
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
-private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void CopyAndAdvance(void *destination, size_t num_bytes);
-
- void Advance(size_t num_bytes);
-
- template<typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
-
- template<typename TS, typename TU>
- TS ConvertUnsignedToSigned(TU value);
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
-};
-
-// Returns a std::vector containing |num_bytes| of input data. If fewer than
-// |num_bytes| of data remain, returns a shorter std::vector containing all
-// of the data that's left. Can be used with any byte sized type, such as
-// char, unsigned char, uint8_t, etc.
-template<typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes)
-{
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
-}
-
-// Similar to |ConsumeBytes|, but also appends the terminator value at the end
-// of the resulting vector. Useful, when a mutable null-terminated C-string is
-// needed, for example. But that is a rare case. Better avoid it, if possible,
-// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
-template<typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes, T terminator)
-{
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
-}
-
-// Returns a std::vector containing all remaining bytes of the input data.
-template<typename T>
-std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes()
-{
- return ConsumeBytes<T>(remaining_bytes_);
-}
-
-// Returns a std::string containing |num_bytes| of input data. Using this and
-// |.c_str()| on the resulting string is the best way to get an immutable
-// null-terminated C string. If fewer than |num_bytes| of data remain, returns
-// a shorter std::string containing all of the data that's left.
-inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes)
-{
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
- Advance(num_bytes);
- return result;
-}
-
-// Returns a std::string of length from 0 to |max_length|. When it runs out of
-// input data, returns what remains of the input. Designed to be more stable
-// with respect to a fuzzer inserting characters than just picking a random
-// length and then consuming that many bytes with |ConsumeBytes|.
-inline std::string FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length)
-{
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
- }
- result += next;
- }
-
- result.shrink_to_fit();
- return result;
-}
-
-// Returns a std::string of length from 0 to |remaining_bytes_|.
-inline std::string FuzzedDataProvider::ConsumeRandomLengthString()
-{
- return ConsumeRandomLengthString(remaining_bytes_);
-}
-
-// Returns a std::string containing all remaining bytes of the input data.
-// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
-// object.
-inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString()
-{
- return ConsumeBytesAsString(remaining_bytes_);
-}
-
-// Returns a number in the range [Type's min, Type's max]. The value might
-// not be uniformly distributed in the given range. If there's no input data
-// left, always returns |min|.
-template<typename T>
-T FuzzedDataProvider::ConsumeIntegral()
-{
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
-}
-
-// Returns a number in the range [min, max] by consuming bytes from the
-// input data. The value might not be uniformly distributed in the given
-// range. If there's no input data left, always returns |min|. |min| must
-// be less than or equal to |max|.
-template<typename T>
-T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max)
-{
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
-
- if (min > max)
- abort();
-
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
-
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
-
- return static_cast<T>(min + result);
-}
-
-// Returns a floating point value in the range [Type's lowest, Type's max] by
-// consuming bytes from the input data. If there's no input data left, always
-// returns approximately 0.
-template<typename T>
-T FuzzedDataProvider::ConsumeFloatingPoint()
-{
- return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
-}
-
-// Returns a floating point value in the given range by consuming bytes from
-// the input data. If there's no input data left, returns |min|. Note that
-// |min| must be less than or equal to |max|.
-template<typename T>
-T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max)
-{
- if (min > max)
- abort();
-
- T range = .0;
- T result = min;
- constexpr T zero(.0);
- if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
- // The diff |max - min| would overflow the given floating point type. Use
- // the half of the diff as the range and consume a bool to decide whether
- // the result is in the first of the second part of the diff.
- range = (max / 2.0) - (min / 2.0);
- if (ConsumeBool()) {
- result += range;
- }
- } else {
- range = max - min;
- }
-
- return result + range * ConsumeProbability<T>();
-}
-
-// Returns a floating point number in the range [0.0, 1.0]. If there's no
-// input data left, always returns 0.
-template<typename T>
-T FuzzedDataProvider::ConsumeProbability()
-{
- static_assert(std::is_floating_point<T>::value, "A floating point type is required.");
-
- // Use different integral types for different floating point types in order
- // to provide better density of the resulting values.
- using IntegralType = typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t, uint64_t>::type;
-
- T result = static_cast<T>(ConsumeIntegral<IntegralType>());
- result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
- return result;
-}
-
-// Reads one byte and returns a bool, or false when no data remains.
-inline bool FuzzedDataProvider::ConsumeBool()
-{
- return 1 & ConsumeIntegral<uint8_t>();
-}
-
-// Returns an enum value. The enum must start at 0 and be contiguous. It must
-// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
-// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
-template<typename T>
-T FuzzedDataProvider::ConsumeEnum()
-{
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
-}
-
-// Returns a copy of the value selected from the given fixed-size |array|.
-template<typename T, size_t size>
-T FuzzedDataProvider::PickValueInArray(const T (&array)[size])
-{
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
-}
-
-template<typename T>
-T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list)
-{
- // TODO(Dor1s): switch to static_assert once C++14 is allowed.
- if (!list.size())
- abort();
-
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
-}
-
-// Writes |num_bytes| of input data to the given destination pointer. If there
-// is not enough data left, writes all remaining bytes. Return value is the
-// number of bytes written.
-// In general, it's better to avoid using this function, but it may be useful
-// in cases when it's necessary to fill a certain buffer or object with
-// fuzzing data.
-inline size_t FuzzedDataProvider::ConsumeData(void *destination, size_t num_bytes)
-{
- num_bytes = std::min(num_bytes, remaining_bytes_);
- CopyAndAdvance(destination, num_bytes);
- return num_bytes;
-}
-
-// Private methods.
-inline void FuzzedDataProvider::CopyAndAdvance(void *destination, size_t num_bytes)
-{
- std::memcpy(destination, data_ptr_, num_bytes);
- Advance(num_bytes);
-}
-
-inline void FuzzedDataProvider::Advance(size_t num_bytes)
-{
- if (num_bytes > remaining_bytes_)
- abort();
-
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
-}
-
-template<typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes)
-{
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- if (size == 0) {
- if (num_bytes != 0)
- abort();
- return result;
- }
-
- CopyAndAdvance(result.data(), num_bytes);
-
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
- return result;
-}
-
-template<typename TS, typename TU>
-TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value)
-{
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed, "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signed conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max()) {
- return static_cast<TS>(value);
- } else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
-}
-
-#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/qt5/tests/fuzzing/fuzzer_temp_file.h b/qt5/tests/fuzzing/fuzzer_temp_file.h
deleted file mode 100644
index d0568ac5..00000000
--- a/qt5/tests/fuzzing/fuzzer_temp_file.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2018 Google Inc.
-//
-// 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.
-
-// Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
-// require a file instead of an input buffer.
-
-#ifndef FUZZER_TEMP_FILE_H_
-#define FUZZER_TEMP_FILE_H_
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-// Pure-C interface for creating and cleaning up temporary files.
-
-static char *fuzzer_get_tmpfile(const uint8_t *data, size_t size)
-{
- char *filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
- if (!filename_buffer) {
- perror("Failed to allocate file name buffer.");
- abort();
- }
- const int file_descriptor = mkstemp(filename_buffer);
- if (file_descriptor < 0) {
- perror("Failed to make temporary file.");
- abort();
- }
- FILE *file = fdopen(file_descriptor, "wb");
- if (!file) {
- perror("Failed to open file descriptor.");
- close(file_descriptor);
- abort();
- }
- const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
- if (bytes_written < size) {
- close(file_descriptor);
- fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)", bytes_written, size);
- abort();
- }
- fclose(file);
- return filename_buffer;
-}
-
-static void fuzzer_release_tmpfile(char *filename)
-{
- if (unlink(filename) != 0) {
- perror("WARNING: Failed to delete temporary file.");
- }
- free(filename);
-}
-
-// C++ RAII object for creating temporary files.
-
-#ifdef __cplusplus
-class FuzzerTemporaryFile
-{
-public:
- FuzzerTemporaryFile(const uint8_t *data, size_t size) : filename_(fuzzer_get_tmpfile(data, size)) { }
-
- ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
-
- const char *filename() const { return filename_; }
-
-private:
- char *filename_;
-};
-#endif
-
-#endif // FUZZER_TEMP_FILE_H_
diff --git a/qt5/tests/fuzzing/qt_annot_fuzzer.cc b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
index 8b569f28..f34af342 100644
--- a/qt5/tests/fuzzing/qt_annot_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
@@ -1,6 +1,6 @@
#include <cstdint>
#include <poppler-qt5.h>
-#include "fuzzer_temp_file.h"
+#include <QtCore/QBuffer>
static void dummy_error_function(const QString &, const QVariant &) { }
@@ -9,14 +9,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
const QFont font(QStringLiteral("Helvetica"), 20);
const QColor color = QColor::fromRgb(0xAB, 0xCD, 0xEF);
- char *tmpfile = fuzzer_get_tmpfile(data, size);
QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
if (!doc || doc->isLocked()) {
delete doc;
- fuzzer_release_tmpfile(tmpfile);
return 0;
}
@@ -32,15 +30,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
ann->setContents(QString(in_data));
p->addAnnotation(ann);
+ QBuffer buffer;
+ buffer.open(QIODevice::WriteOnly);
std::unique_ptr<Poppler::PDFConverter> conv(doc->pdfConverter());
- conv->setOutputFileName(tmpfile);
+ conv->setOutputDevice(&buffer);
conv->setPDFOptions(Poppler::PDFConverter::WithChanges);
conv->convert();
+ buffer.close();
delete ann;
delete p;
}
- fuzzer_release_tmpfile(tmpfile);
delete doc;
return 0;
}
commit 48026f90fd07f3da886ce0079facec49f8022c07
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Fri Oct 23 11:02:20 2020 +0000
Fixing clang_format issues
diff --git a/cpp/tests/fuzzing/FuzzedDataProvider.h b/cpp/tests/fuzzing/FuzzedDataProvider.h
index 83bcd013..1996bcad 100644
--- a/cpp/tests/fuzzing/FuzzedDataProvider.h
+++ b/cpp/tests/fuzzing/FuzzedDataProvider.h
@@ -26,288 +26,308 @@
// In addition to the comments below, the API is also briefly documented at
// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
-class FuzzedDataProvider {
- public:
- // |data| is an array of length |size| that the FuzzedDataProvider wraps to
- // provide more granular access. |data| must outlive the FuzzedDataProvider.
- FuzzedDataProvider(const uint8_t *data, size_t size)
- : data_ptr_(data), remaining_bytes_(size) {}
- ~FuzzedDataProvider() = default;
-
- // See the implementation below (after the class definition) for more verbose
- // comments for each of the methods.
-
- // Methods returning std::vector of bytes. These are the most popular choice
- // when splitting fuzzing input into pieces, as every piece is put into a
- // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
- // will be released automatically.
- template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
- template <typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
- template <typename T> std::vector<T> ConsumeRemainingBytes();
-
- // Methods returning strings. Use only when you need a std::string or a null
- // terminated C-string. Otherwise, prefer the methods returning std::vector.
- std::string ConsumeBytesAsString(size_t num_bytes);
- std::string ConsumeRandomLengthString(size_t max_length);
- std::string ConsumeRandomLengthString();
- std::string ConsumeRemainingBytesAsString();
-
- // Methods returning integer values.
- template <typename T> T ConsumeIntegral();
- template <typename T> T ConsumeIntegralInRange(T min, T max);
-
- // Methods returning floating point values.
- template <typename T> T ConsumeFloatingPoint();
- template <typename T> T ConsumeFloatingPointInRange(T min, T max);
-
- // 0 <= return value <= 1.
- template <typename T> T ConsumeProbability();
-
- bool ConsumeBool();
-
- // Returns a value chosen from the given enum.
- template <typename T> T ConsumeEnum();
-
- // Returns a value from the given array.
- template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
- template <typename T> T PickValueInArray(std::initializer_list<const T> list);
-
- // Writes data to the given destination and returns number of bytes written.
- size_t ConsumeData(void *destination, size_t num_bytes);
-
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
- private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void CopyAndAdvance(void *destination, size_t num_bytes);
-
- void Advance(size_t num_bytes);
-
- template <typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
-
- template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
+class FuzzedDataProvider
+{
+public:
+ // |data| is an array of length |size| that the FuzzedDataProvider wraps to
+ // provide more granular access. |data| must outlive the FuzzedDataProvider.
+ FuzzedDataProvider(const uint8_t *data, size_t size) : data_ptr_(data), remaining_bytes_(size) { }
+ ~FuzzedDataProvider() = default;
+
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
+
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template<typename T>
+ std::vector<T> ConsumeBytes(size_t num_bytes);
+ template<typename T>
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template<typename T>
+ std::vector<T> ConsumeRemainingBytes();
+
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
+
+ // Methods returning integer values.
+ template<typename T>
+ T ConsumeIntegral();
+ template<typename T>
+ T ConsumeIntegralInRange(T min, T max);
+
+ // Methods returning floating point values.
+ template<typename T>
+ T ConsumeFloatingPoint();
+ template<typename T>
+ T ConsumeFloatingPointInRange(T min, T max);
+
+ // 0 <= return value <= 1.
+ template<typename T>
+ T ConsumeProbability();
+
+ bool ConsumeBool();
+
+ // Returns a value chosen from the given enum.
+ template<typename T>
+ T ConsumeEnum();
+
+ // Returns a value from the given array.
+ template<typename T, size_t size>
+ T PickValueInArray(const T (&array)[size]);
+ template<typename T>
+ T PickValueInArray(std::initializer_list<const T> list);
+
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
+
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
+
+private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
+
+ void CopyAndAdvance(void *destination, size_t num_bytes);
+
+ void Advance(size_t num_bytes);
+
+ template<typename T>
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
+
+ template<typename TS, typename TU>
+ TS ConvertUnsignedToSigned(TU value);
+
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
};
// Returns a std::vector containing |num_bytes| of input data. If fewer than
// |num_bytes| of data remain, returns a shorter std::vector containing all
// of the data that's left. Can be used with any byte sized type, such as
// char, unsigned char, uint8_t, etc.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
}
// Similar to |ConsumeBytes|, but also appends the terminator value at the end
// of the resulting vector. Useful, when a mutable null-terminated C-string is
// needed, for example. But that is a rare case. Better avoid it, if possible,
// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
- T terminator) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes, T terminator)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
}
// Returns a std::vector containing all remaining bytes of the input data.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
- return ConsumeBytes<T>(remaining_bytes_);
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes()
+{
+ return ConsumeBytes<T>(remaining_bytes_);
}
// Returns a std::string containing |num_bytes| of input data. Using this and
// |.c_str()| on the resulting string is the best way to get an immutable
// null-terminated C string. If fewer than |num_bytes| of data remain, returns
// a shorter std::string containing all of the data that's left.
-inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
- "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(
- reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
- Advance(num_bytes);
- return result;
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes)
+{
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
}
// Returns a std::string of length from 0 to |max_length|. When it runs out of
// input data, returns what remains of the input. Designed to be more stable
// with respect to a fuzzer inserting characters than just picking a random
// length and then consuming that many bytes with |ConsumeBytes|.
-inline std::string
-FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length)
+{
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
}
- result += next;
- }
- result.shrink_to_fit();
- return result;
+ result.shrink_to_fit();
+ return result;
}
// Returns a std::string of length from 0 to |remaining_bytes_|.
-inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
- return ConsumeRandomLengthString(remaining_bytes_);
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString()
+{
+ return ConsumeRandomLengthString(remaining_bytes_);
}
// Returns a std::string containing all remaining bytes of the input data.
// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
// object.
-inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
- return ConsumeBytesAsString(remaining_bytes_);
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString()
+{
+ return ConsumeBytesAsString(remaining_bytes_);
}
// Returns a number in the range [Type's min, Type's max]. The value might
// not be uniformly distributed in the given range. If there's no input data
// left, always returns |min|.
-template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
+template<typename T>
+T FuzzedDataProvider::ConsumeIntegral()
+{
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
}
// Returns a number in the range [min, max] by consuming bytes from the
// input data. The value might not be uniformly distributed in the given
// range. If there's no input data left, always returns |min|. |min| must
// be less than or equal to |max|.
-template <typename T>
-T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
-
- if (min > max)
- abort();
-
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
- remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
-
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
-
- return static_cast<T>(min + result);
+template<typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max)
+{
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
+ }
+
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
}
// Returns a floating point value in the range [Type's lowest, Type's max] by
// consuming bytes from the input data. If there's no input data left, always
// returns approximately 0.
-template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
- return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
- std::numeric_limits<T>::max());
+template<typename T>
+T FuzzedDataProvider::ConsumeFloatingPoint()
+{
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
}
// Returns a floating point value in the given range by consuming bytes from
// the input data. If there's no input data left, returns |min|. Note that
// |min| must be less than or equal to |max|.
-template <typename T>
-T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
- if (min > max)
- abort();
-
- T range = .0;
- T result = min;
- constexpr T zero(.0);
- if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
- // The diff |max - min| would overflow the given floating point type. Use
- // the half of the diff as the range and consume a bool to decide whether
- // the result is in the first of the second part of the diff.
- range = (max / 2.0) - (min / 2.0);
- if (ConsumeBool()) {
- result += range;
+template<typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max)
+{
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
+ }
+ } else {
+ range = max - min;
}
- } else {
- range = max - min;
- }
- return result + range * ConsumeProbability<T>();
+ return result + range * ConsumeProbability<T>();
}
// Returns a floating point number in the range [0.0, 1.0]. If there's no
// input data left, always returns 0.
-template <typename T> T FuzzedDataProvider::ConsumeProbability() {
- static_assert(std::is_floating_point<T>::value,
- "A floating point type is required.");
-
- // Use different integral types for different floating point types in order
- // to provide better density of the resulting values.
- using IntegralType =
- typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
- uint64_t>::type;
-
- T result = static_cast<T>(ConsumeIntegral<IntegralType>());
- result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
- return result;
+template<typename T>
+T FuzzedDataProvider::ConsumeProbability()
+{
+ static_assert(std::is_floating_point<T>::value, "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType = typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t, uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
}
// Reads one byte and returns a bool, or false when no data remains.
-inline bool FuzzedDataProvider::ConsumeBool() {
- return 1 & ConsumeIntegral<uint8_t>();
+inline bool FuzzedDataProvider::ConsumeBool()
+{
+ return 1 & ConsumeIntegral<uint8_t>();
}
// Returns an enum value. The enum must start at 0 and be contiguous. It must
// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
-template <typename T> T FuzzedDataProvider::ConsumeEnum() {
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(
- ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+template<typename T>
+T FuzzedDataProvider::ConsumeEnum()
+{
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
}
// Returns a copy of the value selected from the given fixed-size |array|.
-template <typename T, size_t size>
-T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+template<typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size])
+{
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
}
-template <typename T>
-T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
- // TODO(Dor1s): switch to static_assert once C++14 is allowed.
- if (!list.size())
- abort();
+template<typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list)
+{
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
}
// Writes |num_bytes| of input data to the given destination pointer. If there
@@ -316,72 +336,74 @@ T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
// In general, it's better to avoid using this function, but it may be useful
// in cases when it's necessary to fill a certain buffer or object with
// fuzzing data.
-inline size_t FuzzedDataProvider::ConsumeData(void *destination,
- size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- CopyAndAdvance(destination, num_bytes);
- return num_bytes;
+inline size_t FuzzedDataProvider::ConsumeData(void *destination, size_t num_bytes)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
}
// Private methods.
-inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
- size_t num_bytes) {
- std::memcpy(destination, data_ptr_, num_bytes);
- Advance(num_bytes);
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination, size_t num_bytes)
+{
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
}
-inline void FuzzedDataProvider::Advance(size_t num_bytes) {
- if (num_bytes > remaining_bytes_)
- abort();
+inline void FuzzedDataProvider::Advance(size_t num_bytes)
+{
+ if (num_bytes > remaining_bytes_)
+ abort();
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
}
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- if (size == 0) {
- if (num_bytes != 0)
- abort();
- return result;
- }
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes)
+{
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
+ abort();
+ return result;
+ }
- CopyAndAdvance(result.data(), num_bytes);
+ CopyAndAdvance(result.data(), num_bytes);
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
- return result;
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
}
-template <typename TS, typename TU>
-TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed,
- "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signed conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max()) {
- return static_cast<TS>(value);
- } else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
+template<typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value)
+{
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed, "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
+ }
}
#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/cpp/tests/fuzzing/doc_fuzzer.cc b/cpp/tests/fuzzing/doc_fuzzer.cc
index 720909d3..b8dd957f 100644
--- a/cpp/tests/fuzzing/doc_fuzzer.cc
+++ b/cpp/tests/fuzzing/doc_fuzzer.cc
@@ -34,12 +34,12 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
doc->set_subject(poppler::ustring::from_latin1(in_sub));
doc->set_title(poppler::ustring::from_latin1(in_title));
- doc->set_author(poppler::ustring::from_utf8((const char*)data,size));
- doc->set_creator(poppler::ustring::from_utf8((const char*)data,size));
- doc->set_keywords(poppler::ustring::from_utf8((const char*)data,size));
- doc->set_producer(poppler::ustring::from_utf8((const char*)data,size));
- doc->set_subject(poppler::ustring::from_utf8((const char*)data,size));
- doc->set_title(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_author(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_creator(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_keywords(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_producer(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_subject(poppler::ustring::from_utf8((const char *)data, size));
+ doc->set_title(poppler::ustring::from_utf8((const char *)data, size));
delete doc;
return 0;
diff --git a/cpp/tests/fuzzing/fuzzer_temp_file.h b/cpp/tests/fuzzing/fuzzer_temp_file.h
index fe25caba..d0568ac5 100644
--- a/cpp/tests/fuzzing/fuzzer_temp_file.h
+++ b/cpp/tests/fuzzing/fuzzer_temp_file.h
@@ -26,56 +26,57 @@
// Pure-C interface for creating and cleaning up temporary files.
-static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
- char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
- if (!filename_buffer) {
- perror("Failed to allocate file name buffer.");
- abort();
- }
- const int file_descriptor = mkstemp(filename_buffer);
- if (file_descriptor < 0) {
- perror("Failed to make temporary file.");
- abort();
- }
- FILE* file = fdopen(file_descriptor, "wb");
- if (!file) {
- perror("Failed to open file descriptor.");
- close(file_descriptor);
- abort();
- }
- const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
- if (bytes_written < size) {
- close(file_descriptor);
- fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
- bytes_written, size);
- abort();
- }
- fclose(file);
- return filename_buffer;
+static char *fuzzer_get_tmpfile(const uint8_t *data, size_t size)
+{
+ char *filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE *file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)", bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
}
-static void fuzzer_release_tmpfile(char* filename) {
- if (unlink(filename) != 0) {
- perror("WARNING: Failed to delete temporary file.");
- }
- free(filename);
+static void fuzzer_release_tmpfile(char *filename)
+{
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
}
// C++ RAII object for creating temporary files.
#ifdef __cplusplus
-class FuzzerTemporaryFile {
- public:
- FuzzerTemporaryFile(const uint8_t* data, size_t size)
- : filename_(fuzzer_get_tmpfile(data, size)) {}
+class FuzzerTemporaryFile
+{
+public:
+ FuzzerTemporaryFile(const uint8_t *data, size_t size) : filename_(fuzzer_get_tmpfile(data, size)) { }
- ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
- const char* filename() const { return filename_; }
+ const char *filename() const { return filename_; }
- private:
- char* filename_;
+private:
+ char *filename_;
};
#endif
-#endif // FUZZER_TEMP_FILE_H_
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/cpp/tests/fuzzing/page_label_fuzzer.cc b/cpp/tests/fuzzing/page_label_fuzzer.cc
index 510ca40d..19106036 100644
--- a/cpp/tests/fuzzing/page_label_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_label_fuzzer.cc
@@ -19,7 +19,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
poppler::page_renderer r;
for (int i = 0; i < doc->pages(); i++) {
- poppler::ustring label = poppler::ustring::from_utf8((const char*)data, size);
+ poppler::ustring label = poppler::ustring::from_utf8((const char *)data, size);
poppler::page *p = doc->create_page(label);
if (!p) {
continue;
diff --git a/cpp/tests/fuzzing/page_search_fuzzer.cc b/cpp/tests/fuzzing/page_search_fuzzer.cc
index 24a4e23c..6427976c 100644
--- a/cpp/tests/fuzzing/page_search_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_search_fuzzer.cc
@@ -24,7 +24,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
continue;
}
poppler::rectf rect = p->page_rect();
- poppler::ustring text = poppler::ustring::from_utf8((const char*)data, size);
+ poppler::ustring text = poppler::ustring::from_utf8((const char *)data, size);
p->search(text, rect, poppler::page::search_from_top, poppler::case_insensitive, poppler::rotate_0);
r.render_page(p);
delete p;
diff --git a/glib/tests/fuzzing/annot_fuzzer.c b/glib/tests/fuzzing/annot_fuzzer.c
index ad2f23d6..db3f0e49 100644
--- a/glib/tests/fuzzing/annot_fuzzer.c
+++ b/glib/tests/fuzzing/annot_fuzzer.c
@@ -5,7 +5,8 @@
#include "fuzzer_temp_file.h"
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.c b/glib/tests/fuzzing/doc_attr_fuzzer.c
index 7fe0ee59..1b62884b 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.c
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.c
@@ -1,7 +1,8 @@
#include <stdint.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
diff --git a/glib/tests/fuzzing/find_text_fuzzer.c b/glib/tests/fuzzing/find_text_fuzzer.c
index 207704a3..744f0051 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.c
+++ b/glib/tests/fuzzing/find_text_fuzzer.c
@@ -1,7 +1,8 @@
#include <stdint.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
diff --git a/glib/tests/fuzzing/fuzzer_temp_file.h b/glib/tests/fuzzing/fuzzer_temp_file.h
index fe25caba..d0568ac5 100644
--- a/glib/tests/fuzzing/fuzzer_temp_file.h
+++ b/glib/tests/fuzzing/fuzzer_temp_file.h
@@ -26,56 +26,57 @@
// Pure-C interface for creating and cleaning up temporary files.
-static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
- char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
- if (!filename_buffer) {
- perror("Failed to allocate file name buffer.");
- abort();
- }
- const int file_descriptor = mkstemp(filename_buffer);
- if (file_descriptor < 0) {
- perror("Failed to make temporary file.");
- abort();
- }
- FILE* file = fdopen(file_descriptor, "wb");
- if (!file) {
- perror("Failed to open file descriptor.");
- close(file_descriptor);
- abort();
- }
- const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
- if (bytes_written < size) {
- close(file_descriptor);
- fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
- bytes_written, size);
- abort();
- }
- fclose(file);
- return filename_buffer;
+static char *fuzzer_get_tmpfile(const uint8_t *data, size_t size)
+{
+ char *filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE *file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)", bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
}
-static void fuzzer_release_tmpfile(char* filename) {
- if (unlink(filename) != 0) {
- perror("WARNING: Failed to delete temporary file.");
- }
- free(filename);
+static void fuzzer_release_tmpfile(char *filename)
+{
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
}
// C++ RAII object for creating temporary files.
#ifdef __cplusplus
-class FuzzerTemporaryFile {
- public:
- FuzzerTemporaryFile(const uint8_t* data, size_t size)
- : filename_(fuzzer_get_tmpfile(data, size)) {}
+class FuzzerTemporaryFile
+{
+public:
+ FuzzerTemporaryFile(const uint8_t *data, size_t size) : filename_(fuzzer_get_tmpfile(data, size)) { }
- ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
- const char* filename() const { return filename_; }
+ const char *filename() const { return filename_; }
- private:
- char* filename_;
+private:
+ char *filename_;
};
#endif
-#endif // FUZZER_TEMP_FILE_H_
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.c
index ee417a55..5475184e 100644
--- a/glib/tests/fuzzing/label_fuzzer.c
+++ b/glib/tests/fuzzing/label_fuzzer.c
@@ -1,7 +1,8 @@
#include <stdint.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
diff --git a/glib/tests/fuzzing/pdf_draw_fuzzer.c b/glib/tests/fuzzing/pdf_draw_fuzzer.c
index f0881e16..fffbdb20 100644
--- a/glib/tests/fuzzing/pdf_draw_fuzzer.c
+++ b/glib/tests/fuzzing/pdf_draw_fuzzer.c
@@ -5,7 +5,8 @@
#include "fuzzer_temp_file.h"
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
@@ -54,7 +55,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (status != CAIRO_STATUS_SUCCESS) {
g_object_unref(page);
continue;
-
}
if (hg) {
cairo_set_source_rgb(cr, 0.6, 0.6, 1.0);
diff --git a/glib/tests/fuzzing/util_fuzzer.c b/glib/tests/fuzzing/util_fuzzer.c
index 752e46d9..01f3c2d4 100644
--- a/glib/tests/fuzzing/util_fuzzer.c
+++ b/glib/tests/fuzzing/util_fuzzer.c
@@ -1,7 +1,8 @@
#include <stdint.h>
#include <poppler.h>
-int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
gsize length;
poppler_named_dest_from_bytestring(data, size);
poppler_named_dest_to_bytestring(data, &length);
diff --git a/qt5/tests/fuzzing/FuzzedDataProvider.h b/qt5/tests/fuzzing/FuzzedDataProvider.h
index 83bcd013..1996bcad 100644
--- a/qt5/tests/fuzzing/FuzzedDataProvider.h
+++ b/qt5/tests/fuzzing/FuzzedDataProvider.h
@@ -26,288 +26,308 @@
// In addition to the comments below, the API is also briefly documented at
// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
-class FuzzedDataProvider {
- public:
- // |data| is an array of length |size| that the FuzzedDataProvider wraps to
- // provide more granular access. |data| must outlive the FuzzedDataProvider.
- FuzzedDataProvider(const uint8_t *data, size_t size)
- : data_ptr_(data), remaining_bytes_(size) {}
- ~FuzzedDataProvider() = default;
-
- // See the implementation below (after the class definition) for more verbose
- // comments for each of the methods.
-
- // Methods returning std::vector of bytes. These are the most popular choice
- // when splitting fuzzing input into pieces, as every piece is put into a
- // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
- // will be released automatically.
- template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
- template <typename T>
- std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
- template <typename T> std::vector<T> ConsumeRemainingBytes();
-
- // Methods returning strings. Use only when you need a std::string or a null
- // terminated C-string. Otherwise, prefer the methods returning std::vector.
- std::string ConsumeBytesAsString(size_t num_bytes);
- std::string ConsumeRandomLengthString(size_t max_length);
- std::string ConsumeRandomLengthString();
- std::string ConsumeRemainingBytesAsString();
-
- // Methods returning integer values.
- template <typename T> T ConsumeIntegral();
- template <typename T> T ConsumeIntegralInRange(T min, T max);
-
- // Methods returning floating point values.
- template <typename T> T ConsumeFloatingPoint();
- template <typename T> T ConsumeFloatingPointInRange(T min, T max);
-
- // 0 <= return value <= 1.
- template <typename T> T ConsumeProbability();
-
- bool ConsumeBool();
-
- // Returns a value chosen from the given enum.
- template <typename T> T ConsumeEnum();
-
- // Returns a value from the given array.
- template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
- template <typename T> T PickValueInArray(std::initializer_list<const T> list);
-
- // Writes data to the given destination and returns number of bytes written.
- size_t ConsumeData(void *destination, size_t num_bytes);
-
- // Reports the remaining bytes available for fuzzed input.
- size_t remaining_bytes() { return remaining_bytes_; }
-
- private:
- FuzzedDataProvider(const FuzzedDataProvider &) = delete;
- FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
-
- void CopyAndAdvance(void *destination, size_t num_bytes);
-
- void Advance(size_t num_bytes);
-
- template <typename T>
- std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
-
- template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
-
- const uint8_t *data_ptr_;
- size_t remaining_bytes_;
+class FuzzedDataProvider
+{
+public:
+ // |data| is an array of length |size| that the FuzzedDataProvider wraps to
+ // provide more granular access. |data| must outlive the FuzzedDataProvider.
+ FuzzedDataProvider(const uint8_t *data, size_t size) : data_ptr_(data), remaining_bytes_(size) { }
+ ~FuzzedDataProvider() = default;
+
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
+
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template<typename T>
+ std::vector<T> ConsumeBytes(size_t num_bytes);
+ template<typename T>
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template<typename T>
+ std::vector<T> ConsumeRemainingBytes();
+
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
+
+ // Methods returning integer values.
+ template<typename T>
+ T ConsumeIntegral();
+ template<typename T>
+ T ConsumeIntegralInRange(T min, T max);
+
+ // Methods returning floating point values.
+ template<typename T>
+ T ConsumeFloatingPoint();
+ template<typename T>
+ T ConsumeFloatingPointInRange(T min, T max);
+
+ // 0 <= return value <= 1.
+ template<typename T>
+ T ConsumeProbability();
+
+ bool ConsumeBool();
+
+ // Returns a value chosen from the given enum.
+ template<typename T>
+ T ConsumeEnum();
+
+ // Returns a value from the given array.
+ template<typename T, size_t size>
+ T PickValueInArray(const T (&array)[size]);
+ template<typename T>
+ T PickValueInArray(std::initializer_list<const T> list);
+
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
+
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
+
+private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
+
+ void CopyAndAdvance(void *destination, size_t num_bytes);
+
+ void Advance(size_t num_bytes);
+
+ template<typename T>
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
+
+ template<typename TS, typename TU>
+ TS ConvertUnsignedToSigned(TU value);
+
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
};
// Returns a std::vector containing |num_bytes| of input data. If fewer than
// |num_bytes| of data remain, returns a shorter std::vector containing all
// of the data that's left. Can be used with any byte sized type, such as
// char, unsigned char, uint8_t, etc.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- return ConsumeBytes<T>(num_bytes, num_bytes);
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
}
// Similar to |ConsumeBytes|, but also appends the terminator value at the end
// of the resulting vector. Useful, when a mutable null-terminated C-string is
// needed, for example. But that is a rare case. Better avoid it, if possible,
// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
- T terminator) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
- result.back() = terminator;
- return result;
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes, T terminator)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
}
// Returns a std::vector containing all remaining bytes of the input data.
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
- return ConsumeBytes<T>(remaining_bytes_);
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes()
+{
+ return ConsumeBytes<T>(remaining_bytes_);
}
// Returns a std::string containing |num_bytes| of input data. Using this and
// |.c_str()| on the resulting string is the best way to get an immutable
// null-terminated C string. If fewer than |num_bytes| of data remain, returns
// a shorter std::string containing all of the data that's left.
-inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
- static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
- "ConsumeBytesAsString cannot convert the data to a string.");
-
- num_bytes = std::min(num_bytes, remaining_bytes_);
- std::string result(
- reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
- Advance(num_bytes);
- return result;
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes)
+{
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t), "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
}
// Returns a std::string of length from 0 to |max_length|. When it runs out of
// input data, returns what remains of the input. Designed to be more stable
// with respect to a fuzzer inserting characters than just picking a random
// length and then consuming that many bytes with |ConsumeBytes|.
-inline std::string
-FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
- // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
- // followed by anything else to the end of the string. As a result of this
- // logic, a fuzzer can insert characters into the string, and the string
- // will be lengthened to include those new characters, resulting in a more
- // stable fuzzer than picking the length of a string independently from
- // picking its contents.
- std::string result;
-
- // Reserve the anticipated capaticity to prevent several reallocations.
- result.reserve(std::min(max_length, remaining_bytes_));
- for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
- char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next == '\\' && remaining_bytes_ != 0) {
- next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
- Advance(1);
- if (next != '\\')
- break;
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length)
+{
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
}
- result += next;
- }
- result.shrink_to_fit();
- return result;
+ result.shrink_to_fit();
+ return result;
}
// Returns a std::string of length from 0 to |remaining_bytes_|.
-inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
- return ConsumeRandomLengthString(remaining_bytes_);
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString()
+{
+ return ConsumeRandomLengthString(remaining_bytes_);
}
// Returns a std::string containing all remaining bytes of the input data.
// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
// object.
-inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
- return ConsumeBytesAsString(remaining_bytes_);
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString()
+{
+ return ConsumeBytesAsString(remaining_bytes_);
}
// Returns a number in the range [Type's min, Type's max]. The value might
// not be uniformly distributed in the given range. If there's no input data
// left, always returns |min|.
-template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
- return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
- std::numeric_limits<T>::max());
+template<typename T>
+T FuzzedDataProvider::ConsumeIntegral()
+{
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
}
// Returns a number in the range [min, max] by consuming bytes from the
// input data. The value might not be uniformly distributed in the given
// range. If there's no input data left, always returns |min|. |min| must
// be less than or equal to |max|.
-template <typename T>
-T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
- static_assert(std::is_integral<T>::value, "An integral type is required.");
- static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
-
- if (min > max)
- abort();
-
- // Use the biggest type possible to hold the range and the result.
- uint64_t range = static_cast<uint64_t>(max) - min;
- uint64_t result = 0;
- size_t offset = 0;
-
- while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
- remaining_bytes_ != 0) {
- // Pull bytes off the end of the seed data. Experimentally, this seems to
- // allow the fuzzer to more easily explore the input space. This makes
- // sense, since it works by modifying inputs that caused new code to run,
- // and this data is often used to encode length of data read by
- // |ConsumeBytes|. Separating out read lengths makes it easier modify the
- // contents of the data that is actually read.
- --remaining_bytes_;
- result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
- offset += CHAR_BIT;
- }
-
- // Avoid division by 0, in case |range + 1| results in overflow.
- if (range != std::numeric_limits<decltype(range)>::max())
- result = result % (range + 1);
-
- return static_cast<T>(min + result);
+template<typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max)
+{
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 && remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
+ }
+
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
}
// Returns a floating point value in the range [Type's lowest, Type's max] by
// consuming bytes from the input data. If there's no input data left, always
// returns approximately 0.
-template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
- return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
- std::numeric_limits<T>::max());
+template<typename T>
+T FuzzedDataProvider::ConsumeFloatingPoint()
+{
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::max());
}
// Returns a floating point value in the given range by consuming bytes from
// the input data. If there's no input data left, returns |min|. Note that
// |min| must be less than or equal to |max|.
-template <typename T>
-T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
- if (min > max)
- abort();
-
- T range = .0;
- T result = min;
- constexpr T zero(.0);
- if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
- // The diff |max - min| would overflow the given floating point type. Use
- // the half of the diff as the range and consume a bool to decide whether
- // the result is in the first of the second part of the diff.
- range = (max / 2.0) - (min / 2.0);
- if (ConsumeBool()) {
- result += range;
+template<typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max)
+{
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
+ }
+ } else {
+ range = max - min;
}
- } else {
- range = max - min;
- }
- return result + range * ConsumeProbability<T>();
+ return result + range * ConsumeProbability<T>();
}
// Returns a floating point number in the range [0.0, 1.0]. If there's no
// input data left, always returns 0.
-template <typename T> T FuzzedDataProvider::ConsumeProbability() {
- static_assert(std::is_floating_point<T>::value,
- "A floating point type is required.");
-
- // Use different integral types for different floating point types in order
- // to provide better density of the resulting values.
- using IntegralType =
- typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
- uint64_t>::type;
-
- T result = static_cast<T>(ConsumeIntegral<IntegralType>());
- result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
- return result;
+template<typename T>
+T FuzzedDataProvider::ConsumeProbability()
+{
+ static_assert(std::is_floating_point<T>::value, "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType = typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t, uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
}
// Reads one byte and returns a bool, or false when no data remains.
-inline bool FuzzedDataProvider::ConsumeBool() {
- return 1 & ConsumeIntegral<uint8_t>();
+inline bool FuzzedDataProvider::ConsumeBool()
+{
+ return 1 & ConsumeIntegral<uint8_t>();
}
// Returns an enum value. The enum must start at 0 and be contiguous. It must
// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
-template <typename T> T FuzzedDataProvider::ConsumeEnum() {
- static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
- return static_cast<T>(
- ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+template<typename T>
+T FuzzedDataProvider::ConsumeEnum()
+{
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
}
// Returns a copy of the value selected from the given fixed-size |array|.
-template <typename T, size_t size>
-T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
- static_assert(size > 0, "The array must be non empty.");
- return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+template<typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size])
+{
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
}
-template <typename T>
-T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
- // TODO(Dor1s): switch to static_assert once C++14 is allowed.
- if (!list.size())
- abort();
+template<typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list)
+{
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
- return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
}
// Writes |num_bytes| of input data to the given destination pointer. If there
@@ -316,72 +336,74 @@ T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
// In general, it's better to avoid using this function, but it may be useful
// in cases when it's necessary to fill a certain buffer or object with
// fuzzing data.
-inline size_t FuzzedDataProvider::ConsumeData(void *destination,
- size_t num_bytes) {
- num_bytes = std::min(num_bytes, remaining_bytes_);
- CopyAndAdvance(destination, num_bytes);
- return num_bytes;
+inline size_t FuzzedDataProvider::ConsumeData(void *destination, size_t num_bytes)
+{
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
}
// Private methods.
-inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
- size_t num_bytes) {
- std::memcpy(destination, data_ptr_, num_bytes);
- Advance(num_bytes);
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination, size_t num_bytes)
+{
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
}
-inline void FuzzedDataProvider::Advance(size_t num_bytes) {
- if (num_bytes > remaining_bytes_)
- abort();
+inline void FuzzedDataProvider::Advance(size_t num_bytes)
+{
+ if (num_bytes > remaining_bytes_)
+ abort();
- data_ptr_ += num_bytes;
- remaining_bytes_ -= num_bytes;
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
}
-template <typename T>
-std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
- static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
-
- // The point of using the size-based constructor below is to increase the
- // odds of having a vector object with capacity being equal to the length.
- // That part is always implementation specific, but at least both libc++ and
- // libstdc++ allocate the requested number of bytes in that constructor,
- // which seems to be a natural choice for other implementations as well.
- // To increase the odds even more, we also call |shrink_to_fit| below.
- std::vector<T> result(size);
- if (size == 0) {
- if (num_bytes != 0)
- abort();
- return result;
- }
+template<typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes)
+{
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
+ abort();
+ return result;
+ }
- CopyAndAdvance(result.data(), num_bytes);
+ CopyAndAdvance(result.data(), num_bytes);
- // Even though |shrink_to_fit| is also implementation specific, we expect it
- // to provide an additional assurance in case vector's constructor allocated
- // a buffer which is larger than the actual amount of data we put inside it.
- result.shrink_to_fit();
- return result;
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
}
-template <typename TS, typename TU>
-TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
- static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
- static_assert(!std::numeric_limits<TU>::is_signed,
- "Source type must be unsigned.");
-
- // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
- if (std::numeric_limits<TS>::is_modulo)
- return static_cast<TS>(value);
-
- // Avoid using implementation-defined unsigned to signed conversions.
- // To learn more, see https://stackoverflow.com/questions/13150449.
- if (value <= std::numeric_limits<TS>::max()) {
- return static_cast<TS>(value);
- } else {
- constexpr auto TS_min = std::numeric_limits<TS>::min();
- return TS_min + static_cast<char>(value - TS_min);
- }
+template<typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value)
+{
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed, "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
+ }
}
#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/qt5/tests/fuzzing/fuzzer_temp_file.h b/qt5/tests/fuzzing/fuzzer_temp_file.h
index fe25caba..d0568ac5 100644
--- a/qt5/tests/fuzzing/fuzzer_temp_file.h
+++ b/qt5/tests/fuzzing/fuzzer_temp_file.h
@@ -26,56 +26,57 @@
// Pure-C interface for creating and cleaning up temporary files.
-static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
- char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
- if (!filename_buffer) {
- perror("Failed to allocate file name buffer.");
- abort();
- }
- const int file_descriptor = mkstemp(filename_buffer);
- if (file_descriptor < 0) {
- perror("Failed to make temporary file.");
- abort();
- }
- FILE* file = fdopen(file_descriptor, "wb");
- if (!file) {
- perror("Failed to open file descriptor.");
- close(file_descriptor);
- abort();
- }
- const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
- if (bytes_written < size) {
- close(file_descriptor);
- fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
- bytes_written, size);
- abort();
- }
- fclose(file);
- return filename_buffer;
+static char *fuzzer_get_tmpfile(const uint8_t *data, size_t size)
+{
+ char *filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE *file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)", bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
}
-static void fuzzer_release_tmpfile(char* filename) {
- if (unlink(filename) != 0) {
- perror("WARNING: Failed to delete temporary file.");
- }
- free(filename);
+static void fuzzer_release_tmpfile(char *filename)
+{
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
}
// C++ RAII object for creating temporary files.
#ifdef __cplusplus
-class FuzzerTemporaryFile {
- public:
- FuzzerTemporaryFile(const uint8_t* data, size_t size)
- : filename_(fuzzer_get_tmpfile(data, size)) {}
+class FuzzerTemporaryFile
+{
+public:
+ FuzzerTemporaryFile(const uint8_t *data, size_t size) : filename_(fuzzer_get_tmpfile(data, size)) { }
- ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
- const char* filename() const { return filename_; }
+ const char *filename() const { return filename_; }
- private:
- char* filename_;
+private:
+ char *filename_;
};
#endif
-#endif // FUZZER_TEMP_FILE_H_
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/qt5/tests/fuzzing/qt_annot_fuzzer.cc b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
index 1e6de148..8b569f28 100644
--- a/qt5/tests/fuzzing/qt_annot_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
@@ -11,17 +11,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
const QColor color = QColor::fromRgb(0xAB, 0xCD, 0xEF);
char *tmpfile = fuzzer_get_tmpfile(data, size);
- QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
- if (!doc || doc->isLocked()){
+ if (!doc || doc->isLocked()) {
delete doc;
fuzzer_release_tmpfile(tmpfile);
return 0;
}
for (int i = 0; i < doc->numPages(); i++) {
- Poppler::Page* p = doc->page(i);
+ Poppler::Page *p = doc->page(i);
if (!p) {
continue;
}
diff --git a/qt5/tests/fuzzing/qt_label_fuzzer.cc b/qt5/tests/fuzzing/qt_label_fuzzer.cc
index 64049fcc..65a81629 100644
--- a/qt5/tests/fuzzing/qt_label_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_label_fuzzer.cc
@@ -7,16 +7,16 @@ static void dummy_error_function(const QString &, const QVariant &) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
- QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
- if (!doc || doc->isLocked()){
+ if (!doc || doc->isLocked()) {
delete doc;
return 0;
}
for (int i = 0; i < doc->numPages(); i++) {
QString label = QString(in_data);
- Poppler::Page* p = doc->page(label);
+ Poppler::Page *p = doc->page(label);
if (!p) {
continue;
}
diff --git a/qt5/tests/fuzzing/qt_pdf_fuzzer.cc b/qt5/tests/fuzzing/qt_pdf_fuzzer.cc
index 1398b28a..82786994 100644
--- a/qt5/tests/fuzzing/qt_pdf_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_pdf_fuzzer.cc
@@ -7,15 +7,15 @@ static void dummy_error_function(const QString &, const QVariant &) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
- QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
- if (!doc || doc->isLocked()){
+ if (!doc || doc->isLocked()) {
delete doc;
return 0;
}
for (int i = 0; i < doc->numPages(); i++) {
- Poppler::Page* p = doc->page(i);
+ Poppler::Page *p = doc->page(i);
if (!p) {
continue;
}
diff --git a/qt5/tests/fuzzing/qt_search_fuzzer.cc b/qt5/tests/fuzzing/qt_search_fuzzer.cc
index 6d00720a..989589fd 100644
--- a/qt5/tests/fuzzing/qt_search_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_search_fuzzer.cc
@@ -6,15 +6,15 @@ static void dummy_error_function(const QString &, const QVariant &) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
- QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
- if (!doc || doc->isLocked()){
+ if (!doc || doc->isLocked()) {
delete doc;
return 0;
}
for (int i = 0; i < doc->numPages(); i++) {
- Poppler::Page* p = doc->page(i);
+ Poppler::Page *p = doc->page(i);
if (!p) {
continue;
}
diff --git a/qt5/tests/fuzzing/qt_textbox_fuzzer.cc b/qt5/tests/fuzzing/qt_textbox_fuzzer.cc
index e90dbaab..c0ecef74 100644
--- a/qt5/tests/fuzzing/qt_textbox_fuzzer.cc
+++ b/qt5/tests/fuzzing/qt_textbox_fuzzer.cc
@@ -8,15 +8,15 @@ static void dummy_error_function(const QString &, const QVariant &) { }
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
- QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ QByteArray in_data = QByteArray::fromRawData((const char *)data, size);
Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
- if (!doc || doc->isLocked()){
+ if (!doc || doc->isLocked()) {
delete doc;
return 0;
}
for (int i = 0; i < doc->numPages(); i++) {
- Poppler::Page* p = doc->page(i);
+ Poppler::Page *p = doc->page(i);
if (!p) {
continue;
}
commit 890de69dbe531484f687877124c080508b25a9f8
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Mon Oct 19 08:23:48 2020 +0000
Fuzzers for qt5 + cleaning up cpp and glib fuzzers
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index 9517b39a..18b17334 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -21,7 +21,7 @@ cpp_add_simpletest(poppler-dump poppler-dump.cpp ${CMAKE_SOURCE_DIR}/utils/parse
cpp_add_simpletest(poppler-render poppler-render.cpp ${CMAKE_SOURCE_DIR}/utils/parseargs.cc)
if(ENABLE_FUZZER)
- cpp_add_simpletest(pdf_fuzzer pdf_fuzzer.cc)
+ cpp_add_simpletest(doc_fuzzer ./fuzzing/doc_fuzzer.cc)
cpp_add_simpletest(pdf_file_fuzzer ./fuzzing/pdf_file_fuzzer.cc)
cpp_add_simpletest(page_label_fuzzer ./fuzzing/page_label_fuzzer.cc)
cpp_add_simpletest(page_search_fuzzer ./fuzzing/page_search_fuzzer.cc)
diff --git a/cpp/tests/fuzzing/FuzzedDataProvider.h b/cpp/tests/fuzzing/FuzzedDataProvider.h
new file mode 100644
index 00000000..83bcd013
--- /dev/null
+++ b/cpp/tests/fuzzing/FuzzedDataProvider.h
@@ -0,0 +1,387 @@
+//===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// A single header library providing an utility class to break up an array of
+// bytes. Whenever run on the same input, provides the same output, as long as
+// its methods are called in the same order, with the same arguments.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
+#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
+
+#include <algorithm>
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <initializer_list>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+// In addition to the comments below, the API is also briefly documented at
+// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
+class FuzzedDataProvider {
+ public:
+ // |data| is an array of length |size| that the FuzzedDataProvider wraps to
+ // provide more granular access. |data| must outlive the FuzzedDataProvider.
+ FuzzedDataProvider(const uint8_t *data, size_t size)
+ : data_ptr_(data), remaining_bytes_(size) {}
+ ~FuzzedDataProvider() = default;
+
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
+
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
+ template <typename T>
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template <typename T> std::vector<T> ConsumeRemainingBytes();
+
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
+
+ // Methods returning integer values.
+ template <typename T> T ConsumeIntegral();
+ template <typename T> T ConsumeIntegralInRange(T min, T max);
+
+ // Methods returning floating point values.
+ template <typename T> T ConsumeFloatingPoint();
+ template <typename T> T ConsumeFloatingPointInRange(T min, T max);
+
+ // 0 <= return value <= 1.
+ template <typename T> T ConsumeProbability();
+
+ bool ConsumeBool();
+
+ // Returns a value chosen from the given enum.
+ template <typename T> T ConsumeEnum();
+
+ // Returns a value from the given array.
+ template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
+ template <typename T> T PickValueInArray(std::initializer_list<const T> list);
+
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
+
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
+
+ private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
+
+ void CopyAndAdvance(void *destination, size_t num_bytes);
+
+ void Advance(size_t num_bytes);
+
+ template <typename T>
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
+
+ template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
+
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
+};
+
+// Returns a std::vector containing |num_bytes| of input data. If fewer than
+// |num_bytes| of data remain, returns a shorter std::vector containing all
+// of the data that's left. Can be used with any byte sized type, such as
+// char, unsigned char, uint8_t, etc.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
+}
+
+// Similar to |ConsumeBytes|, but also appends the terminator value at the end
+// of the resulting vector. Useful, when a mutable null-terminated C-string is
+// needed, for example. But that is a rare case. Better avoid it, if possible,
+// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
+ T terminator) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
+}
+
+// Returns a std::vector containing all remaining bytes of the input data.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
+ return ConsumeBytes<T>(remaining_bytes_);
+}
+
+// Returns a std::string containing |num_bytes| of input data. Using this and
+// |.c_str()| on the resulting string is the best way to get an immutable
+// null-terminated C string. If fewer than |num_bytes| of data remain, returns
+// a shorter std::string containing all of the data that's left.
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
+ "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(
+ reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
+}
+
+// Returns a std::string of length from 0 to |max_length|. When it runs out of
+// input data, returns what remains of the input. Designed to be more stable
+// with respect to a fuzzer inserting characters than just picking a random
+// length and then consuming that many bytes with |ConsumeBytes|.
+inline std::string
+FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
+ }
+
+ result.shrink_to_fit();
+ return result;
+}
+
+// Returns a std::string of length from 0 to |remaining_bytes_|.
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
+ return ConsumeRandomLengthString(remaining_bytes_);
+}
+
+// Returns a std::string containing all remaining bytes of the input data.
+// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
+// object.
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
+ return ConsumeBytesAsString(remaining_bytes_);
+}
+
+// Returns a number in the range [Type's min, Type's max]. The value might
+// not be uniformly distributed in the given range. If there's no input data
+// left, always returns |min|.
+template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a number in the range [min, max] by consuming bytes from the
+// input data. The value might not be uniformly distributed in the given
+// range. If there's no input data left, always returns |min|. |min| must
+// be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
+ remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
+ }
+
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
+}
+
+// Returns a floating point value in the range [Type's lowest, Type's max] by
+// consuming bytes from the input data. If there's no input data left, always
+// returns approximately 0.
+template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a floating point value in the given range by consuming bytes from
+// the input data. If there's no input data left, returns |min|. Note that
+// |min| must be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
+ }
+ } else {
+ range = max - min;
+ }
+
+ return result + range * ConsumeProbability<T>();
+}
+
+// Returns a floating point number in the range [0.0, 1.0]. If there's no
+// input data left, always returns 0.
+template <typename T> T FuzzedDataProvider::ConsumeProbability() {
+ static_assert(std::is_floating_point<T>::value,
+ "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType =
+ typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
+ uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
+}
+
+// Reads one byte and returns a bool, or false when no data remains.
+inline bool FuzzedDataProvider::ConsumeBool() {
+ return 1 & ConsumeIntegral<uint8_t>();
+}
+
+// Returns an enum value. The enum must start at 0 and be contiguous. It must
+// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
+// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
+template <typename T> T FuzzedDataProvider::ConsumeEnum() {
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(
+ ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+}
+
+// Returns a copy of the value selected from the given fixed-size |array|.
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
+
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+}
+
+// Writes |num_bytes| of input data to the given destination pointer. If there
+// is not enough data left, writes all remaining bytes. Return value is the
+// number of bytes written.
+// In general, it's better to avoid using this function, but it may be useful
+// in cases when it's necessary to fill a certain buffer or object with
+// fuzzing data.
+inline size_t FuzzedDataProvider::ConsumeData(void *destination,
+ size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
+}
+
+// Private methods.
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
+ size_t num_bytes) {
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
+}
+
+inline void FuzzedDataProvider::Advance(size_t num_bytes) {
+ if (num_bytes > remaining_bytes_)
+ abort();
+
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
+}
+
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
+ abort();
+ return result;
+ }
+
+ CopyAndAdvance(result.data(), num_bytes);
+
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
+}
+
+template <typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed,
+ "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
+ }
+}
+
+#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/cpp/tests/fuzzing/doc_fuzzer.cc b/cpp/tests/fuzzing/doc_fuzzer.cc
new file mode 100644
index 00000000..720909d3
--- /dev/null
+++ b/cpp/tests/fuzzing/doc_fuzzer.cc
@@ -0,0 +1,46 @@
+#include <cstdint>
+
+#include <poppler-global.h>
+#include <poppler-document.h>
+#include <poppler-page.h>
+#include "FuzzedDataProvider.h"
+
+#define INPUT_SIZE 32
+
+static void dummy_error_function(const std::string &, void *) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ poppler::set_debug_error_function(dummy_error_function, nullptr);
+ poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
+ if (!doc || doc->is_locked()) {
+ delete doc;
+ return 0;
+ }
+
+ FuzzedDataProvider data_provider(data, size);
+ std::string in_auth = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_creat = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_key = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_prod = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_sub = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+ std::string in_title = data_provider.ConsumeBytesAsString(INPUT_SIZE);
+
+ // Testing both methods for conversion to ustring
+ doc->set_author(poppler::ustring::from_latin1(in_auth));
+ doc->set_creator(poppler::ustring::from_latin1(in_creat));
+ doc->set_keywords(poppler::ustring::from_latin1(in_key));
+ doc->set_producer(poppler::ustring::from_latin1(in_prod));
+ doc->set_subject(poppler::ustring::from_latin1(in_sub));
+ doc->set_title(poppler::ustring::from_latin1(in_title));
+
+ doc->set_author(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_creator(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_keywords(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_producer(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_subject(poppler::ustring::from_utf8((const char*)data,size));
+ doc->set_title(poppler::ustring::from_utf8((const char*)data,size));
+
+ delete doc;
+ return 0;
+}
diff --git a/cpp/tests/fuzzing/page_label_fuzzer.cc b/cpp/tests/fuzzing/page_label_fuzzer.cc
index ca168da3..510ca40d 100644
--- a/cpp/tests/fuzzing/page_label_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_label_fuzzer.cc
@@ -1,21 +1,3 @@
-/*
-# Copyright 2018 Google Inc.
-#
-# 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.
-#
-################################################################################
-*/
-
#include <cstdint>
#include <poppler-global.h>
diff --git a/cpp/tests/fuzzing/page_search_fuzzer.cc b/cpp/tests/fuzzing/page_search_fuzzer.cc
index 99fc99aa..24a4e23c 100644
--- a/cpp/tests/fuzzing/page_search_fuzzer.cc
+++ b/cpp/tests/fuzzing/page_search_fuzzer.cc
@@ -1,21 +1,3 @@
-/*
-# Copyright 2018 Google Inc.
-#
-# 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.
-#
-################################################################################
-*/
-
#include <cstdint>
#include <poppler-global.h>
diff --git a/cpp/tests/fuzzing/pdf_file_fuzzer.cc b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
index 6ee40e29..6a682a17 100644
--- a/cpp/tests/fuzzing/pdf_file_fuzzer.cc
+++ b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
@@ -1,21 +1,3 @@
-/*
-# Copyright 2018 Google Inc.
-#
-# 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.
-#
-################################################################################
-*/
-
#include <cstdint>
#include <string>
diff --git a/glib/tests/fuzzing/annot_fuzzer.c b/glib/tests/fuzzing/annot_fuzzer.c
index 3748e5d9..ad2f23d6 100644
--- a/glib/tests/fuzzing/annot_fuzzer.c
+++ b/glib/tests/fuzzing/annot_fuzzer.c
@@ -1,5 +1,9 @@
#include <stdint.h>
#include <poppler.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+
+#include "fuzzer_temp_file.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
GError *err = NULL;
@@ -7,8 +11,13 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
PopplerPage *page;
PopplerAnnot *annot;
PopplerRectangle bb;
+ gdouble width, height;
gboolean hg;
- int npages, n;
+ int npages;
+
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_status_t status;
doc = poppler_document_new_from_data(data, size, NULL, &err);
if (doc == NULL) {
@@ -17,22 +26,53 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
npages = poppler_document_get_n_pages(doc);
if (npages < 1) {
+ g_object_unref(doc);
+ return 0;
+ }
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ surface = cairo_pdf_surface_create(tmpfile, 1.0, 1.0);
+ status = cairo_surface_status(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ g_object_unref(doc);
+ fuzzer_release_tmpfile(tmpfile);
return 0;
}
- for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ for (int n = 0; n < npages; n++) {
page = poppler_document_get_page(doc, n);
if (!page) {
continue;
}
+
+ poppler_page_get_size(page, &width, &height);
+ cairo_pdf_surface_set_size(surface, width, height);
hg = poppler_page_get_bounding_box(page, &bb);
if (hg) {
annot = poppler_annot_text_new(doc, &bb);
+ if (annot != NULL) {
+ g_object_unref(page);
+ continue;
+ }
poppler_page_add_annot(page, annot);
- poppler_annot_set_contents(annot, data);
- poppler_annot_markup_set_label(annot, data);
+ /*poppler_annot_set_contents(annot, data);*/
+ /*poppler_annot_markup_set_label(annot, data);*/
+ }
+
+ cr = cairo_create(surface);
+ status = cairo_status(cr);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ cairo_destroy(cr);
+ g_object_unref(page);
+ continue;
}
+ poppler_page_render_for_printing(page, cr);
+ cairo_surface_show_page(surface);
+ cairo_destroy(cr);
g_object_unref(page);
}
+ cairo_surface_destroy(surface);
+ fuzzer_release_tmpfile(tmpfile);
+ g_object_unref(doc);
return 0;
}
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.c b/glib/tests/fuzzing/doc_attr_fuzzer.c
index bf4531b2..7fe0ee59 100644
--- a/glib/tests/fuzzing/doc_attr_fuzzer.c
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.c
@@ -1,6 +1,5 @@
#include <stdint.h>
#include <poppler.h>
-#include <cairo.h>
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
GError *err = NULL;
diff --git a/glib/tests/fuzzing/find_text_fuzzer.c b/glib/tests/fuzzing/find_text_fuzzer.c
index f1611328..207704a3 100644
--- a/glib/tests/fuzzing/find_text_fuzzer.c
+++ b/glib/tests/fuzzing/find_text_fuzzer.c
@@ -1,12 +1,11 @@
#include <stdint.h>
#include <poppler.h>
-#include <cairo.h>
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
- int npages, n;
+ int npages;
doc = poppler_document_new_from_data(data, size, NULL, &err);
if (doc == NULL) {
@@ -19,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
return 0;
}
- for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ for (int n = 0; n < npages; n++) {
page = poppler_document_get_page(doc, n);
if (!page) {
continue;
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.c
index e70f6644..ee417a55 100644
--- a/glib/tests/fuzzing/label_fuzzer.c
+++ b/glib/tests/fuzzing/label_fuzzer.c
@@ -1,12 +1,11 @@
#include <stdint.h>
#include <poppler.h>
-#include <cairo.h>
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
GError *err = NULL;
PopplerDocument *doc;
PopplerPage *page;
- int npages, n;
+ int npages;
doc = poppler_document_new_from_data(data, size, NULL, &err);
if (doc == NULL) {
@@ -19,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
return 0;
}
- for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ for (int n = 0; n < npages; n++) {
page = poppler_document_get_page_by_label(doc, data);
if (!page) {
continue;
diff --git a/glib/tests/fuzzing/pdf_draw_fuzzer.c b/glib/tests/fuzzing/pdf_draw_fuzzer.c
index 24abdc43..f0881e16 100644
--- a/glib/tests/fuzzing/pdf_draw_fuzzer.c
+++ b/glib/tests/fuzzing/pdf_draw_fuzzer.c
@@ -12,10 +12,11 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
PopplerRectangle bb;
gdouble width, height;
gboolean hg;
- int npages, n;
+ int npages;
- cairo_surface_t *surface;
cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_status_t status;
doc = poppler_document_new_from_data(data, size, NULL, &err);
if (doc == NULL) {
@@ -31,31 +32,43 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
char *tmpfile = fuzzer_get_tmpfile(data, size);
surface = cairo_pdf_surface_create(tmpfile, 1.0, 1.0);
+ status = cairo_surface_status(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ g_object_unref(doc);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
- for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ for (int n = 0; n < npages; n++) {
page = poppler_document_get_page(doc, n);
if (!page) {
continue;
}
+
poppler_page_get_size(page, &width, &height);
cairo_pdf_surface_set_size(surface, width, height);
hg = poppler_page_get_bounding_box(page, &bb);
cr = cairo_create(surface);
- poppler_page_render_for_printing(page, cr);
+ status = cairo_status(cr);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ g_object_unref(page);
+ continue;
+
+ }
if (hg) {
- cairo_set_source_rgb(cr, 1.6, 1.6, 1.6);
+ cairo_set_source_rgb(cr, 0.6, 0.6, 1.0);
cairo_rectangle(cr, bb.x1, bb.y1, bb.x2 - bb.x1, bb.y2 - bb.y1);
cairo_stroke(cr);
}
- cairo_destroy(cr);
- cairo_surface_show_page(surface);
+ poppler_page_render_for_printing(page, cr);
+ cairo_surface_show_page(surface);
+ cairo_destroy(cr);
g_object_unref(page);
}
-
- g_object_unref(doc);
cairo_surface_destroy(surface);
+ g_object_unref(doc);
fuzzer_release_tmpfile(tmpfile);
return 0;
}
diff --git a/glib/tests/fuzzing/util_fuzzer.c b/glib/tests/fuzzing/util_fuzzer.c
index 3514cd73..752e46d9 100644
--- a/glib/tests/fuzzing/util_fuzzer.c
+++ b/glib/tests/fuzzing/util_fuzzer.c
@@ -1,12 +1,9 @@
#include <stdint.h>
#include <poppler.h>
-#include <cairo.h>
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
gsize length;
poppler_named_dest_from_bytestring(data, size);
poppler_named_dest_to_bytestring(data, &length);
- /*poppler_named_dest_from_bytestring((const guint8*)data, size);*/
- /*poppler_named_dest_to_bytestring((const char*)data, &length);*/
return 0;
}
diff --git a/qt5/tests/CMakeLists.txt b/qt5/tests/CMakeLists.txt
index 5f542440..b8b5a399 100644
--- a/qt5/tests/CMakeLists.txt
+++ b/qt5/tests/CMakeLists.txt
@@ -43,6 +43,14 @@ macro(QT5_ADD_QTEST exe source)
endif ()
endmacro(QT5_ADD_QTEST)
+macro(QT_ADD_FUZZER exe)
+ string(REPLACE "-" "" test_name ${exe})
+ set(${test_name}_SOURCES
+ ${ARGN}
+ )
+ poppler_add_test(${exe} BUILD_QT5_TESTS ${${test_name}_SOURCES})
+ target_link_libraries(${exe} poppler-qt5 ${Qt5Widgets_LIBRARIES} ${Qt5Test_LIBRARIES} ${Qt5Core_LIBRARIES} ${Qt5Gui_LIBRARIES})
+endmacro(QT_ADD_FUZZER)
qt5_add_simpletest(test-poppler-qt5 test-poppler-qt5.cpp)
qt5_add_simpletest(test-password-qt5 test-password-qt5.cpp)
@@ -80,3 +88,11 @@ if (NOT WIN32)
qt5_add_qtest(check_qt5_pagelabelinfo check_pagelabelinfo.cpp)
qt5_add_qtest(check_qt5_strings check_strings.cpp)
endif ()
+
+if(ENABLE_FUZZER)
+ qt_add_fuzzer(qt_annot_fuzzer ./fuzzing/qt_annot_fuzzer.cc)
+ qt_add_fuzzer(qt_pdf_fuzzer ./fuzzing/qt_pdf_fuzzer.cc)
+ qt_add_fuzzer(qt_label_fuzzer ./fuzzing/qt_label_fuzzer.cc)
+ qt_add_fuzzer(qt_search_fuzzer ./fuzzing/qt_search_fuzzer.cc)
+ qt_add_fuzzer(qt_textbox_fuzzer ./fuzzing/qt_textbox_fuzzer.cc)
+endif()
diff --git a/qt5/tests/fuzzing/FuzzedDataProvider.h b/qt5/tests/fuzzing/FuzzedDataProvider.h
new file mode 100644
index 00000000..83bcd013
--- /dev/null
+++ b/qt5/tests/fuzzing/FuzzedDataProvider.h
@@ -0,0 +1,387 @@
+//===- FuzzedDataProvider.h - Utility header for fuzz targets ---*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// A single header library providing an utility class to break up an array of
+// bytes. Whenever run on the same input, provides the same output, as long as
+// its methods are called in the same order, with the same arguments.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
+#define LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
+
+#include <algorithm>
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <initializer_list>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+// In addition to the comments below, the API is also briefly documented at
+// https://github.com/google/fuzzing/blob/master/docs/split-inputs.md#fuzzed-data-provider
+class FuzzedDataProvider {
+ public:
+ // |data| is an array of length |size| that the FuzzedDataProvider wraps to
+ // provide more granular access. |data| must outlive the FuzzedDataProvider.
+ FuzzedDataProvider(const uint8_t *data, size_t size)
+ : data_ptr_(data), remaining_bytes_(size) {}
+ ~FuzzedDataProvider() = default;
+
+ // See the implementation below (after the class definition) for more verbose
+ // comments for each of the methods.
+
+ // Methods returning std::vector of bytes. These are the most popular choice
+ // when splitting fuzzing input into pieces, as every piece is put into a
+ // separate buffer (i.e. ASan would catch any under-/overflow) and the memory
+ // will be released automatically.
+ template <typename T> std::vector<T> ConsumeBytes(size_t num_bytes);
+ template <typename T>
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes, T terminator = 0);
+ template <typename T> std::vector<T> ConsumeRemainingBytes();
+
+ // Methods returning strings. Use only when you need a std::string or a null
+ // terminated C-string. Otherwise, prefer the methods returning std::vector.
+ std::string ConsumeBytesAsString(size_t num_bytes);
+ std::string ConsumeRandomLengthString(size_t max_length);
+ std::string ConsumeRandomLengthString();
+ std::string ConsumeRemainingBytesAsString();
+
+ // Methods returning integer values.
+ template <typename T> T ConsumeIntegral();
+ template <typename T> T ConsumeIntegralInRange(T min, T max);
+
+ // Methods returning floating point values.
+ template <typename T> T ConsumeFloatingPoint();
+ template <typename T> T ConsumeFloatingPointInRange(T min, T max);
+
+ // 0 <= return value <= 1.
+ template <typename T> T ConsumeProbability();
+
+ bool ConsumeBool();
+
+ // Returns a value chosen from the given enum.
+ template <typename T> T ConsumeEnum();
+
+ // Returns a value from the given array.
+ template <typename T, size_t size> T PickValueInArray(const T (&array)[size]);
+ template <typename T> T PickValueInArray(std::initializer_list<const T> list);
+
+ // Writes data to the given destination and returns number of bytes written.
+ size_t ConsumeData(void *destination, size_t num_bytes);
+
+ // Reports the remaining bytes available for fuzzed input.
+ size_t remaining_bytes() { return remaining_bytes_; }
+
+ private:
+ FuzzedDataProvider(const FuzzedDataProvider &) = delete;
+ FuzzedDataProvider &operator=(const FuzzedDataProvider &) = delete;
+
+ void CopyAndAdvance(void *destination, size_t num_bytes);
+
+ void Advance(size_t num_bytes);
+
+ template <typename T>
+ std::vector<T> ConsumeBytes(size_t size, size_t num_bytes);
+
+ template <typename TS, typename TU> TS ConvertUnsignedToSigned(TU value);
+
+ const uint8_t *data_ptr_;
+ size_t remaining_bytes_;
+};
+
+// Returns a std::vector containing |num_bytes| of input data. If fewer than
+// |num_bytes| of data remain, returns a shorter std::vector containing all
+// of the data that's left. Can be used with any byte sized type, such as
+// char, unsigned char, uint8_t, etc.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ return ConsumeBytes<T>(num_bytes, num_bytes);
+}
+
+// Similar to |ConsumeBytes|, but also appends the terminator value at the end
+// of the resulting vector. Useful, when a mutable null-terminated C-string is
+// needed, for example. But that is a rare case. Better avoid it, if possible,
+// and prefer using |ConsumeBytes| or |ConsumeBytesAsString| methods.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytesWithTerminator(size_t num_bytes,
+ T terminator) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::vector<T> result = ConsumeBytes<T>(num_bytes + 1, num_bytes);
+ result.back() = terminator;
+ return result;
+}
+
+// Returns a std::vector containing all remaining bytes of the input data.
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeRemainingBytes() {
+ return ConsumeBytes<T>(remaining_bytes_);
+}
+
+// Returns a std::string containing |num_bytes| of input data. Using this and
+// |.c_str()| on the resulting string is the best way to get an immutable
+// null-terminated C string. If fewer than |num_bytes| of data remain, returns
+// a shorter std::string containing all of the data that's left.
+inline std::string FuzzedDataProvider::ConsumeBytesAsString(size_t num_bytes) {
+ static_assert(sizeof(std::string::value_type) == sizeof(uint8_t),
+ "ConsumeBytesAsString cannot convert the data to a string.");
+
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ std::string result(
+ reinterpret_cast<const std::string::value_type *>(data_ptr_), num_bytes);
+ Advance(num_bytes);
+ return result;
+}
+
+// Returns a std::string of length from 0 to |max_length|. When it runs out of
+// input data, returns what remains of the input. Designed to be more stable
+// with respect to a fuzzer inserting characters than just picking a random
+// length and then consuming that many bytes with |ConsumeBytes|.
+inline std::string
+FuzzedDataProvider::ConsumeRandomLengthString(size_t max_length) {
+ // Reads bytes from the start of |data_ptr_|. Maps "\\" to "\", and maps "\"
+ // followed by anything else to the end of the string. As a result of this
+ // logic, a fuzzer can insert characters into the string, and the string
+ // will be lengthened to include those new characters, resulting in a more
+ // stable fuzzer than picking the length of a string independently from
+ // picking its contents.
+ std::string result;
+
+ // Reserve the anticipated capaticity to prevent several reallocations.
+ result.reserve(std::min(max_length, remaining_bytes_));
+ for (size_t i = 0; i < max_length && remaining_bytes_ != 0; ++i) {
+ char next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next == '\\' && remaining_bytes_ != 0) {
+ next = ConvertUnsignedToSigned<char>(data_ptr_[0]);
+ Advance(1);
+ if (next != '\\')
+ break;
+ }
+ result += next;
+ }
+
+ result.shrink_to_fit();
+ return result;
+}
+
+// Returns a std::string of length from 0 to |remaining_bytes_|.
+inline std::string FuzzedDataProvider::ConsumeRandomLengthString() {
+ return ConsumeRandomLengthString(remaining_bytes_);
+}
+
+// Returns a std::string containing all remaining bytes of the input data.
+// Prefer using |ConsumeRemainingBytes| unless you actually need a std::string
+// object.
+inline std::string FuzzedDataProvider::ConsumeRemainingBytesAsString() {
+ return ConsumeBytesAsString(remaining_bytes_);
+}
+
+// Returns a number in the range [Type's min, Type's max]. The value might
+// not be uniformly distributed in the given range. If there's no input data
+// left, always returns |min|.
+template <typename T> T FuzzedDataProvider::ConsumeIntegral() {
+ return ConsumeIntegralInRange(std::numeric_limits<T>::min(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a number in the range [min, max] by consuming bytes from the
+// input data. The value might not be uniformly distributed in the given
+// range. If there's no input data left, always returns |min|. |min| must
+// be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeIntegralInRange(T min, T max) {
+ static_assert(std::is_integral<T>::value, "An integral type is required.");
+ static_assert(sizeof(T) <= sizeof(uint64_t), "Unsupported integral type.");
+
+ if (min > max)
+ abort();
+
+ // Use the biggest type possible to hold the range and the result.
+ uint64_t range = static_cast<uint64_t>(max) - min;
+ uint64_t result = 0;
+ size_t offset = 0;
+
+ while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0 &&
+ remaining_bytes_ != 0) {
+ // Pull bytes off the end of the seed data. Experimentally, this seems to
+ // allow the fuzzer to more easily explore the input space. This makes
+ // sense, since it works by modifying inputs that caused new code to run,
+ // and this data is often used to encode length of data read by
+ // |ConsumeBytes|. Separating out read lengths makes it easier modify the
+ // contents of the data that is actually read.
+ --remaining_bytes_;
+ result = (result << CHAR_BIT) | data_ptr_[remaining_bytes_];
+ offset += CHAR_BIT;
+ }
+
+ // Avoid division by 0, in case |range + 1| results in overflow.
+ if (range != std::numeric_limits<decltype(range)>::max())
+ result = result % (range + 1);
+
+ return static_cast<T>(min + result);
+}
+
+// Returns a floating point value in the range [Type's lowest, Type's max] by
+// consuming bytes from the input data. If there's no input data left, always
+// returns approximately 0.
+template <typename T> T FuzzedDataProvider::ConsumeFloatingPoint() {
+ return ConsumeFloatingPointInRange<T>(std::numeric_limits<T>::lowest(),
+ std::numeric_limits<T>::max());
+}
+
+// Returns a floating point value in the given range by consuming bytes from
+// the input data. If there's no input data left, returns |min|. Note that
+// |min| must be less than or equal to |max|.
+template <typename T>
+T FuzzedDataProvider::ConsumeFloatingPointInRange(T min, T max) {
+ if (min > max)
+ abort();
+
+ T range = .0;
+ T result = min;
+ constexpr T zero(.0);
+ if (max > zero && min < zero && max > min + std::numeric_limits<T>::max()) {
+ // The diff |max - min| would overflow the given floating point type. Use
+ // the half of the diff as the range and consume a bool to decide whether
+ // the result is in the first of the second part of the diff.
+ range = (max / 2.0) - (min / 2.0);
+ if (ConsumeBool()) {
+ result += range;
+ }
+ } else {
+ range = max - min;
+ }
+
+ return result + range * ConsumeProbability<T>();
+}
+
+// Returns a floating point number in the range [0.0, 1.0]. If there's no
+// input data left, always returns 0.
+template <typename T> T FuzzedDataProvider::ConsumeProbability() {
+ static_assert(std::is_floating_point<T>::value,
+ "A floating point type is required.");
+
+ // Use different integral types for different floating point types in order
+ // to provide better density of the resulting values.
+ using IntegralType =
+ typename std::conditional<(sizeof(T) <= sizeof(uint32_t)), uint32_t,
+ uint64_t>::type;
+
+ T result = static_cast<T>(ConsumeIntegral<IntegralType>());
+ result /= static_cast<T>(std::numeric_limits<IntegralType>::max());
+ return result;
+}
+
+// Reads one byte and returns a bool, or false when no data remains.
+inline bool FuzzedDataProvider::ConsumeBool() {
+ return 1 & ConsumeIntegral<uint8_t>();
+}
+
+// Returns an enum value. The enum must start at 0 and be contiguous. It must
+// also contain |kMaxValue| aliased to its largest (inclusive) value. Such as:
+// enum class Foo { SomeValue, OtherValue, kMaxValue = OtherValue };
+template <typename T> T FuzzedDataProvider::ConsumeEnum() {
+ static_assert(std::is_enum<T>::value, "|T| must be an enum type.");
+ return static_cast<T>(
+ ConsumeIntegralInRange<uint32_t>(0, static_cast<uint32_t>(T::kMaxValue)));
+}
+
+// Returns a copy of the value selected from the given fixed-size |array|.
+template <typename T, size_t size>
+T FuzzedDataProvider::PickValueInArray(const T (&array)[size]) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[ConsumeIntegralInRange<size_t>(0, size - 1)];
+}
+
+template <typename T>
+T FuzzedDataProvider::PickValueInArray(std::initializer_list<const T> list) {
+ // TODO(Dor1s): switch to static_assert once C++14 is allowed.
+ if (!list.size())
+ abort();
+
+ return *(list.begin() + ConsumeIntegralInRange<size_t>(0, list.size() - 1));
+}
+
+// Writes |num_bytes| of input data to the given destination pointer. If there
+// is not enough data left, writes all remaining bytes. Return value is the
+// number of bytes written.
+// In general, it's better to avoid using this function, but it may be useful
+// in cases when it's necessary to fill a certain buffer or object with
+// fuzzing data.
+inline size_t FuzzedDataProvider::ConsumeData(void *destination,
+ size_t num_bytes) {
+ num_bytes = std::min(num_bytes, remaining_bytes_);
+ CopyAndAdvance(destination, num_bytes);
+ return num_bytes;
+}
+
+// Private methods.
+inline void FuzzedDataProvider::CopyAndAdvance(void *destination,
+ size_t num_bytes) {
+ std::memcpy(destination, data_ptr_, num_bytes);
+ Advance(num_bytes);
+}
+
+inline void FuzzedDataProvider::Advance(size_t num_bytes) {
+ if (num_bytes > remaining_bytes_)
+ abort();
+
+ data_ptr_ += num_bytes;
+ remaining_bytes_ -= num_bytes;
+}
+
+template <typename T>
+std::vector<T> FuzzedDataProvider::ConsumeBytes(size_t size, size_t num_bytes) {
+ static_assert(sizeof(T) == sizeof(uint8_t), "Incompatible data type.");
+
+ // The point of using the size-based constructor below is to increase the
+ // odds of having a vector object with capacity being equal to the length.
+ // That part is always implementation specific, but at least both libc++ and
+ // libstdc++ allocate the requested number of bytes in that constructor,
+ // which seems to be a natural choice for other implementations as well.
+ // To increase the odds even more, we also call |shrink_to_fit| below.
+ std::vector<T> result(size);
+ if (size == 0) {
+ if (num_bytes != 0)
+ abort();
+ return result;
+ }
+
+ CopyAndAdvance(result.data(), num_bytes);
+
+ // Even though |shrink_to_fit| is also implementation specific, we expect it
+ // to provide an additional assurance in case vector's constructor allocated
+ // a buffer which is larger than the actual amount of data we put inside it.
+ result.shrink_to_fit();
+ return result;
+}
+
+template <typename TS, typename TU>
+TS FuzzedDataProvider::ConvertUnsignedToSigned(TU value) {
+ static_assert(sizeof(TS) == sizeof(TU), "Incompatible data types.");
+ static_assert(!std::numeric_limits<TU>::is_signed,
+ "Source type must be unsigned.");
+
+ // TODO(Dor1s): change to `if constexpr` once C++17 becomes mainstream.
+ if (std::numeric_limits<TS>::is_modulo)
+ return static_cast<TS>(value);
+
+ // Avoid using implementation-defined unsigned to signed conversions.
+ // To learn more, see https://stackoverflow.com/questions/13150449.
+ if (value <= std::numeric_limits<TS>::max()) {
+ return static_cast<TS>(value);
+ } else {
+ constexpr auto TS_min = std::numeric_limits<TS>::min();
+ return TS_min + static_cast<char>(value - TS_min);
+ }
+}
+
+#endif // LLVM_FUZZER_FUZZED_DATA_PROVIDER_H_
diff --git a/qt5/tests/fuzzing/fuzzer_temp_file.h b/qt5/tests/fuzzing/fuzzer_temp_file.h
new file mode 100644
index 00000000..fe25caba
--- /dev/null
+++ b/qt5/tests/fuzzing/fuzzer_temp_file.h
@@ -0,0 +1,81 @@
+// Copyright 2018 Google Inc.
+//
+// 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.
+
+// Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
+// require a file instead of an input buffer.
+
+#ifndef FUZZER_TEMP_FILE_H_
+#define FUZZER_TEMP_FILE_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// Pure-C interface for creating and cleaning up temporary files.
+
+static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
+ char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE* file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
+ bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
+}
+
+static void fuzzer_release_tmpfile(char* filename) {
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
+}
+
+// C++ RAII object for creating temporary files.
+
+#ifdef __cplusplus
+class FuzzerTemporaryFile {
+ public:
+ FuzzerTemporaryFile(const uint8_t* data, size_t size)
+ : filename_(fuzzer_get_tmpfile(data, size)) {}
+
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+
+ const char* filename() const { return filename_; }
+
+ private:
+ char* filename_;
+};
+#endif
+
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/qt5/tests/fuzzing/qt_annot_fuzzer.cc b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
new file mode 100644
index 00000000..1e6de148
--- /dev/null
+++ b/qt5/tests/fuzzing/qt_annot_fuzzer.cc
@@ -0,0 +1,46 @@
+#include <cstdint>
+#include <poppler-qt5.h>
+#include "fuzzer_temp_file.h"
+
+static void dummy_error_function(const QString &, const QVariant &) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
+ const QFont font(QStringLiteral("Helvetica"), 20);
+ const QColor color = QColor::fromRgb(0xAB, 0xCD, 0xEF);
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+
+ QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
+
+ if (!doc || doc->isLocked()){
+ delete doc;
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ for (int i = 0; i < doc->numPages(); i++) {
+ Poppler::Page* p = doc->page(i);
+ if (!p) {
+ continue;
+ }
+ Poppler::TextAnnotation *ann = new Poppler::TextAnnotation(Poppler::TextAnnotation::InPlace);
+ ann->setTextFont(font);
+ ann->setTextColor(color);
+ ann->setBoundary(QRectF(0.1, 0.1, 0.2, 0.2));
+ ann->setContents(QString(in_data));
+ p->addAnnotation(ann);
+
+ std::unique_ptr<Poppler::PDFConverter> conv(doc->pdfConverter());
+ conv->setOutputFileName(tmpfile);
+ conv->setPDFOptions(Poppler::PDFConverter::WithChanges);
+ conv->convert();
+ delete ann;
+ delete p;
+ }
+
+ fuzzer_release_tmpfile(tmpfile);
+ delete doc;
+ return 0;
+}
diff --git a/qt5/tests/fuzzing/qt_label_fuzzer.cc b/qt5/tests/fuzzing/qt_label_fuzzer.cc
new file mode 100644
index 00000000..64049fcc
--- /dev/null
+++ b/qt5/tests/fuzzing/qt_label_fuzzer.cc
@@ -0,0 +1,29 @@
+#include <cstdint>
+#include <poppler-qt5.h>
+#include <QtGui/QImage>
+
+static void dummy_error_function(const QString &, const QVariant &) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
+ QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
+ if (!doc || doc->isLocked()){
+ delete doc;
+ return 0;
+ }
+
+ for (int i = 0; i < doc->numPages(); i++) {
+ QString label = QString(in_data);
+ Poppler::Page* p = doc->page(label);
+ if (!p) {
+ continue;
+ }
+ QImage image = p->renderToImage(72.0, 72.0, -1, -1, -1, -1, Poppler::Page::Rotate0);
+ delete p;
+ }
+
+ delete doc;
+ return 0;
+}
diff --git a/qt5/tests/fuzzing/qt_pdf_fuzzer.cc b/qt5/tests/fuzzing/qt_pdf_fuzzer.cc
new file mode 100644
index 00000000..1398b28a
--- /dev/null
+++ b/qt5/tests/fuzzing/qt_pdf_fuzzer.cc
@@ -0,0 +1,27 @@
+#include <cstdint>
+#include <poppler-qt5.h>
+#include <QtGui/QImage>
+
+static void dummy_error_function(const QString &, const QVariant &) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
+ QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
+ if (!doc || doc->isLocked()){
+ delete doc;
+ return 0;
+ }
+
+ for (int i = 0; i < doc->numPages(); i++) {
+ Poppler::Page* p = doc->page(i);
+ if (!p) {
+ continue;
+ }
+ QImage image = p->renderToImage(72.0, 72.0, -1, -1, -1, -1, Poppler::Page::Rotate0);
+ delete p;
+ }
+ delete doc;
+ return 0;
+}
diff --git a/qt5/tests/fuzzing/qt_search_fuzzer.cc b/qt5/tests/fuzzing/qt_search_fuzzer.cc
new file mode 100644
index 00000000..6d00720a
--- /dev/null
+++ b/qt5/tests/fuzzing/qt_search_fuzzer.cc
@@ -0,0 +1,28 @@
+#include <cstdint>
+#include <poppler-qt5.h>
+
+static void dummy_error_function(const QString &, const QVariant &) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
+ QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
+ if (!doc || doc->isLocked()){
+ delete doc;
+ return 0;
+ }
+
+ for (int i = 0; i < doc->numPages(); i++) {
+ Poppler::Page* p = doc->page(i);
+ if (!p) {
+ continue;
+ }
+ QString text = QString(in_data);
+ p->search(text, Poppler::Page::IgnoreCase, Poppler::Page::Rotate0);
+ delete p;
+ }
+
+ delete doc;
+ return 0;
+}
diff --git a/qt5/tests/fuzzing/qt_textbox_fuzzer.cc b/qt5/tests/fuzzing/qt_textbox_fuzzer.cc
new file mode 100644
index 00000000..e90dbaab
--- /dev/null
+++ b/qt5/tests/fuzzing/qt_textbox_fuzzer.cc
@@ -0,0 +1,32 @@
+#include <cstdint>
+#include <poppler-qt5.h>
+#include <QtGui/QImage>
+#include <QtGui/QPainter>
+
+static void dummy_error_function(const QString &, const QVariant &) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ Poppler::setDebugErrorFunction(dummy_error_function, QVariant());
+ QByteArray in_data = QByteArray::fromRawData((const char*)data, size);
+ Poppler::Document *doc = Poppler::Document::loadFromData(in_data);
+ if (!doc || doc->isLocked()){
+ delete doc;
+ return 0;
+ }
+
+ for (int i = 0; i < doc->numPages(); i++) {
+ Poppler::Page* p = doc->page(i);
+ if (!p) {
+ continue;
+ }
+ QRectF rf = QRectF(0.0, 0.0, 1.0, 1.0);
+ Poppler::TextBox tb(QString(in_data), rf);
+ QImage image = p->renderToImage(72.0, 72.0, -1, -1, -1, -1, Poppler::Page::Rotate0);
+ QPainter painter(&image);
+ painter.drawRect(tb.boundingBox());
+ delete p;
+ }
+ delete doc;
+ return 0;
+}
commit 8b991bcf392c6c7e8957f4e18f3ca9437fcf4797
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Mon Oct 12 23:05:37 2020 +0000
Fuzzers for glib
diff --git a/glib/tests/CMakeLists.txt b/glib/tests/CMakeLists.txt
index 5f49511c..12f933b6 100644
--- a/glib/tests/CMakeLists.txt
+++ b/glib/tests/CMakeLists.txt
@@ -52,3 +52,21 @@ poppler_add_testcase(poppler-check-bb type3.pdf -p 10 125.80 130 509.30 695 125.
add_executable(pdfdrawbb pdfdrawbb.c)
target_link_libraries(pdfdrawbb poppler-glib)
+
+macro(GLIB_ADD_FUZZER exe)
+ string(REPLACE "-" "" test_name ${exe})
+ set(${test_name}_SOURCES
+ ${ARGN}
+ )
+ poppler_add_test(${exe} BUILD_GTK_TESTS ${${test_name}_SOURCES})
+ target_link_libraries(${exe} poppler-glib ${GTK3_LIBRARIES})
+endmacro(GLIB_ADD_FUZZER)
+
+if(ENABLE_FUZZER)
+ glib_add_fuzzer(annot_fuzzer ./fuzzing/annot_fuzzer.c)
+ glib_add_fuzzer(doc_attr_fuzzer ./fuzzing/doc_attr_fuzzer.c)
+ glib_add_fuzzer(find_text_fuzzer ./fuzzing/find_text_fuzzer.c)
+ glib_add_fuzzer(util_fuzzer ./fuzzing/util_fuzzer.c)
+ glib_add_fuzzer(label_fuzzer ./fuzzing/label_fuzzer.c)
+ glib_add_fuzzer(pdf_draw_fuzzer ./fuzzing/pdf_draw_fuzzer.c)
+endif()
diff --git a/glib/tests/fuzzing/annot_fuzzer.c b/glib/tests/fuzzing/annot_fuzzer.c
new file mode 100644
index 00000000..3748e5d9
--- /dev/null
+++ b/glib/tests/fuzzing/annot_fuzzer.c
@@ -0,0 +1,38 @@
+#include <stdint.h>
+#include <poppler.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ GError *err = NULL;
+ PopplerDocument *doc;
+ PopplerPage *page;
+ PopplerAnnot *annot;
+ PopplerRectangle bb;
+ gboolean hg;
+ int npages, n;
+
+ doc = poppler_document_new_from_data(data, size, NULL, &err);
+ if (doc == NULL) {
+ g_error_free(err);
+ return 0;
+ }
+ npages = poppler_document_get_n_pages(doc);
+ if (npages < 1) {
+ return 0;
+ }
+
+ for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ page = poppler_document_get_page(doc, n);
+ if (!page) {
+ continue;
+ }
+ hg = poppler_page_get_bounding_box(page, &bb);
+ if (hg) {
+ annot = poppler_annot_text_new(doc, &bb);
+ poppler_page_add_annot(page, annot);
+ poppler_annot_set_contents(annot, data);
+ poppler_annot_markup_set_label(annot, data);
+ }
+ g_object_unref(page);
+ }
+ return 0;
+}
diff --git a/glib/tests/fuzzing/doc_attr_fuzzer.c b/glib/tests/fuzzing/doc_attr_fuzzer.c
new file mode 100644
index 00000000..bf4531b2
--- /dev/null
+++ b/glib/tests/fuzzing/doc_attr_fuzzer.c
@@ -0,0 +1,23 @@
+#include <stdint.h>
+#include <poppler.h>
+#include <cairo.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ GError *err = NULL;
+ PopplerDocument *doc;
+ PopplerPage *page;
+ int npages, n;
+
+ doc = poppler_document_new_from_data(data, size, NULL, &err);
+ if (doc == NULL) {
+ g_error_free(err);
+ return 0;
+ }
+ poppler_document_set_author(doc, data);
+ poppler_document_set_creator(doc, data);
+ poppler_document_set_keywords(doc, data);
+ poppler_document_set_producer(doc, data);
+ poppler_document_set_subject(doc, data);
+ poppler_document_set_title(doc, data);
+ return 0;
+}
diff --git a/glib/tests/fuzzing/find_text_fuzzer.c b/glib/tests/fuzzing/find_text_fuzzer.c
new file mode 100644
index 00000000..f1611328
--- /dev/null
+++ b/glib/tests/fuzzing/find_text_fuzzer.c
@@ -0,0 +1,31 @@
+#include <stdint.h>
+#include <poppler.h>
+#include <cairo.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ GError *err = NULL;
+ PopplerDocument *doc;
+ PopplerPage *page;
+ int npages, n;
+
+ doc = poppler_document_new_from_data(data, size, NULL, &err);
+ if (doc == NULL) {
+ g_error_free(err);
+ return 0;
+ }
+
+ npages = poppler_document_get_n_pages(doc);
+ if (npages < 1) {
+ return 0;
+ }
+
+ for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ page = poppler_document_get_page(doc, n);
+ if (!page) {
+ continue;
+ }
+ poppler_page_find_text(page, data);
+ g_object_unref(page);
+ }
+ return 0;
+}
diff --git a/glib/tests/fuzzing/fuzzer_temp_file.h b/glib/tests/fuzzing/fuzzer_temp_file.h
new file mode 100644
index 00000000..fe25caba
--- /dev/null
+++ b/glib/tests/fuzzing/fuzzer_temp_file.h
@@ -0,0 +1,81 @@
+// Copyright 2018 Google Inc.
+//
+// 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.
+
+// Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
+// require a file instead of an input buffer.
+
+#ifndef FUZZER_TEMP_FILE_H_
+#define FUZZER_TEMP_FILE_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// Pure-C interface for creating and cleaning up temporary files.
+
+static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
+ char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE* file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
+ bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
+}
+
+static void fuzzer_release_tmpfile(char* filename) {
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
+}
+
+// C++ RAII object for creating temporary files.
+
+#ifdef __cplusplus
+class FuzzerTemporaryFile {
+ public:
+ FuzzerTemporaryFile(const uint8_t* data, size_t size)
+ : filename_(fuzzer_get_tmpfile(data, size)) {}
+
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+
+ const char* filename() const { return filename_; }
+
+ private:
+ char* filename_;
+};
+#endif
+
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/glib/tests/fuzzing/label_fuzzer.c b/glib/tests/fuzzing/label_fuzzer.c
new file mode 100644
index 00000000..e70f6644
--- /dev/null
+++ b/glib/tests/fuzzing/label_fuzzer.c
@@ -0,0 +1,30 @@
+#include <stdint.h>
+#include <poppler.h>
+#include <cairo.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ GError *err = NULL;
+ PopplerDocument *doc;
+ PopplerPage *page;
+ int npages, n;
+
+ doc = poppler_document_new_from_data(data, size, NULL, &err);
+ if (doc == NULL) {
+ g_error_free(err);
+ return 0;
+ }
+
+ npages = poppler_document_get_n_pages(doc);
+ if (npages < 1) {
+ return 0;
+ }
+
+ for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ page = poppler_document_get_page_by_label(doc, data);
+ if (!page) {
+ continue;
+ }
+ g_object_unref(page);
+ }
+ return 0;
+}
diff --git a/glib/tests/fuzzing/pdf_draw_fuzzer.c b/glib/tests/fuzzing/pdf_draw_fuzzer.c
new file mode 100644
index 00000000..24abdc43
--- /dev/null
+++ b/glib/tests/fuzzing/pdf_draw_fuzzer.c
@@ -0,0 +1,61 @@
+#include <stdint.h>
+#include <poppler.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+
+#include "fuzzer_temp_file.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ GError *err = NULL;
+ PopplerDocument *doc;
+ PopplerPage *page;
+ PopplerRectangle bb;
+ gdouble width, height;
+ gboolean hg;
+ int npages, n;
+
+ cairo_surface_t *surface;
+ cairo_t *cr;
+
+ doc = poppler_document_new_from_data(data, size, NULL, &err);
+ if (doc == NULL) {
+ g_error_free(err);
+ return 0;
+ }
+
+ npages = poppler_document_get_n_pages(doc);
+ if (npages < 1) {
+ g_object_unref(doc);
+ return 0;
+ }
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ surface = cairo_pdf_surface_create(tmpfile, 1.0, 1.0);
+
+ for (n = 0; n < poppler_document_get_n_pages(doc); n++) {
+ page = poppler_document_get_page(doc, n);
+ if (!page) {
+ continue;
+ }
+ poppler_page_get_size(page, &width, &height);
+ cairo_pdf_surface_set_size(surface, width, height);
+ hg = poppler_page_get_bounding_box(page, &bb);
+
+ cr = cairo_create(surface);
+ poppler_page_render_for_printing(page, cr);
+ if (hg) {
+ cairo_set_source_rgb(cr, 1.6, 1.6, 1.6);
+ cairo_rectangle(cr, bb.x1, bb.y1, bb.x2 - bb.x1, bb.y2 - bb.y1);
+ cairo_stroke(cr);
+ }
+ cairo_destroy(cr);
+ cairo_surface_show_page(surface);
+
+ g_object_unref(page);
+ }
+
+ g_object_unref(doc);
+ cairo_surface_destroy(surface);
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}
diff --git a/glib/tests/fuzzing/util_fuzzer.c b/glib/tests/fuzzing/util_fuzzer.c
new file mode 100644
index 00000000..3514cd73
--- /dev/null
+++ b/glib/tests/fuzzing/util_fuzzer.c
@@ -0,0 +1,12 @@
+#include <stdint.h>
+#include <poppler.h>
+#include <cairo.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ gsize length;
+ poppler_named_dest_from_bytestring(data, size);
+ poppler_named_dest_to_bytestring(data, &length);
+ /*poppler_named_dest_from_bytestring((const guint8*)data, size);*/
+ /*poppler_named_dest_to_bytestring((const char*)data, &length);*/
+ return 0;
+}
commit c6a50e4f2334d130061b03c31ad96387ba86dbea
Author: Ceyhun Alp <ceyhunalp at google.com>
Date: Sat Oct 10 20:19:39 2020 +0000
Fuzzers for cpp
diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt
index f5be4213..9517b39a 100644
--- a/cpp/tests/CMakeLists.txt
+++ b/cpp/tests/CMakeLists.txt
@@ -22,4 +22,7 @@ cpp_add_simpletest(poppler-render poppler-render.cpp ${CMAKE_SOURCE_DIR}/utils/p
if(ENABLE_FUZZER)
cpp_add_simpletest(pdf_fuzzer pdf_fuzzer.cc)
+ cpp_add_simpletest(pdf_file_fuzzer ./fuzzing/pdf_file_fuzzer.cc)
+ cpp_add_simpletest(page_label_fuzzer ./fuzzing/page_label_fuzzer.cc)
+ cpp_add_simpletest(page_search_fuzzer ./fuzzing/page_search_fuzzer.cc)
endif()
diff --git a/cpp/tests/fuzzing/fuzzer_temp_file.h b/cpp/tests/fuzzing/fuzzer_temp_file.h
new file mode 100644
index 00000000..fe25caba
--- /dev/null
+++ b/cpp/tests/fuzzing/fuzzer_temp_file.h
@@ -0,0 +1,81 @@
+// Copyright 2018 Google Inc.
+//
+// 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.
+
+// Adapter utility from fuzzer input to a temporary file, for fuzzing APIs that
+// require a file instead of an input buffer.
+
+#ifndef FUZZER_TEMP_FILE_H_
+#define FUZZER_TEMP_FILE_H_
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// Pure-C interface for creating and cleaning up temporary files.
+
+static char* fuzzer_get_tmpfile(const uint8_t* data, size_t size) {
+ char* filename_buffer = strdup("/tmp/generate_temporary_file.XXXXXX");
+ if (!filename_buffer) {
+ perror("Failed to allocate file name buffer.");
+ abort();
+ }
+ const int file_descriptor = mkstemp(filename_buffer);
+ if (file_descriptor < 0) {
+ perror("Failed to make temporary file.");
+ abort();
+ }
+ FILE* file = fdopen(file_descriptor, "wb");
+ if (!file) {
+ perror("Failed to open file descriptor.");
+ close(file_descriptor);
+ abort();
+ }
+ const size_t bytes_written = fwrite(data, sizeof(uint8_t), size, file);
+ if (bytes_written < size) {
+ close(file_descriptor);
+ fprintf(stderr, "Failed to write all bytes to file (%zu out of %zu)",
+ bytes_written, size);
+ abort();
+ }
+ fclose(file);
+ return filename_buffer;
+}
+
+static void fuzzer_release_tmpfile(char* filename) {
+ if (unlink(filename) != 0) {
+ perror("WARNING: Failed to delete temporary file.");
+ }
+ free(filename);
+}
+
+// C++ RAII object for creating temporary files.
+
+#ifdef __cplusplus
+class FuzzerTemporaryFile {
+ public:
+ FuzzerTemporaryFile(const uint8_t* data, size_t size)
+ : filename_(fuzzer_get_tmpfile(data, size)) {}
+
+ ~FuzzerTemporaryFile() { fuzzer_release_tmpfile(filename_); }
+
+ const char* filename() const { return filename_; }
+
+ private:
+ char* filename_;
+};
+#endif
+
+#endif // FUZZER_TEMP_FILE_H_
diff --git a/cpp/tests/fuzzing/page_label_fuzzer.cc b/cpp/tests/fuzzing/page_label_fuzzer.cc
new file mode 100644
index 00000000..ca168da3
--- /dev/null
+++ b/cpp/tests/fuzzing/page_label_fuzzer.cc
@@ -0,0 +1,51 @@
+/*
+# Copyright 2018 Google Inc.
+#
+# 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.
+#
+################################################################################
+*/
+
+#include <cstdint>
+
+#include <poppler-global.h>
+#include <poppler-document.h>
+#include <poppler-page.h>
+#include <poppler-page-renderer.h>
+
+static void dummy_error_function(const std::string &, void *) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ poppler::set_debug_error_function(dummy_error_function, nullptr);
+
+ poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
+ if (!doc || doc->is_locked()) {
+ delete doc;
+ return 0;
+ }
+
+ poppler::page_renderer r;
+ for (int i = 0; i < doc->pages(); i++) {
+ poppler::ustring label = poppler::ustring::from_utf8((const char*)data, size);
+ poppler::page *p = doc->create_page(label);
+ if (!p) {
+ continue;
+ }
+ r.render_page(p);
+ delete p;
+ }
+
+ delete doc;
+ return 0;
+}
diff --git a/cpp/tests/fuzzing/page_search_fuzzer.cc b/cpp/tests/fuzzing/page_search_fuzzer.cc
new file mode 100644
index 00000000..99fc99aa
--- /dev/null
+++ b/cpp/tests/fuzzing/page_search_fuzzer.cc
@@ -0,0 +1,53 @@
+/*
+# Copyright 2018 Google Inc.
+#
+# 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.
+#
+################################################################################
+*/
+
+#include <cstdint>
+
+#include <poppler-global.h>
+#include <poppler-document.h>
+#include <poppler-page.h>
+#include <poppler-page-renderer.h>
+
+static void dummy_error_function(const std::string &, void *) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ poppler::set_debug_error_function(dummy_error_function, nullptr);
+
+ poppler::document *doc = poppler::document::load_from_raw_data((const char *)data, size);
+ if (!doc || doc->is_locked()) {
+ delete doc;
+ return 0;
+ }
+
+ poppler::page_renderer r;
+ for (int i = 0; i < doc->pages(); i++) {
+ poppler::page *p = doc->create_page(i);
+ if (!p) {
+ continue;
+ }
+ poppler::rectf rect = p->page_rect();
+ poppler::ustring text = poppler::ustring::from_utf8((const char*)data, size);
+ p->search(text, rect, poppler::page::search_from_top, poppler::case_insensitive, poppler::rotate_0);
+ r.render_page(p);
+ delete p;
+ }
+
+ delete doc;
+ return 0;
+}
diff --git a/cpp/tests/fuzzing/pdf_file_fuzzer.cc b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
new file mode 100644
index 00000000..6ee40e29
--- /dev/null
+++ b/cpp/tests/fuzzing/pdf_file_fuzzer.cc
@@ -0,0 +1,57 @@
+/*
+# Copyright 2018 Google Inc.
+#
+# 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.
+#
+################################################################################
+*/
+
+#include <cstdint>
+#include <string>
+
+#include <poppler-global.h>
+#include <poppler-document.h>
+#include <poppler-page.h>
+#include <poppler-page-renderer.h>
+
+#include "fuzzer_temp_file.h"
+
+static void dummy_error_function(const std::string &, void *) { }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ poppler::set_debug_error_function(dummy_error_function, nullptr);
+
+ char *tmpfile = fuzzer_get_tmpfile(data, size);
+ std::string fname(tmpfile);
+ poppler::document *doc = poppler::document::load_from_file(fname);
+ if (!doc || doc->is_locked()) {
+ delete doc;
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+ }
+
+ poppler::page_renderer r;
+ for (int i = 0; i < doc->pages(); i++) {
+ poppler::page *p = doc->create_page(i);
+ if (!p) {
+ continue;
+ }
+ r.render_page(p);
+ delete p;
+ }
+
+ delete doc;
+ fuzzer_release_tmpfile(tmpfile);
+ return 0;
+}
More information about the poppler
mailing list