/src/poppler/glib/tests/fuzzing/structured_text_fuzzer.cc
Line | Count | Source |
1 | | // Fuzzer for PDF structured text parser |
2 | | |
3 | | #include <stdint.h> |
4 | | #include <stdlib.h> |
5 | | #include <poppler.h> |
6 | | #include <GlobalParams.h> |
7 | | |
8 | | // Recursive function to exercise structure tree parsing |
9 | | static void exercise_structure_tree(PopplerStructureElementIter *iter) |
10 | 52.9k | { |
11 | 52.9k | if (!iter) { |
12 | 0 | return; |
13 | 0 | } |
14 | | |
15 | 168k | do { |
16 | 168k | PopplerStructureElement *element = poppler_structure_element_iter_get_element(iter); |
17 | 168k | if (!element) { |
18 | 0 | continue; |
19 | 0 | } |
20 | | |
21 | | // Exercise all getter functions |
22 | 168k | (void)poppler_structure_element_get_kind(element); |
23 | | |
24 | | // These return gchar* that should be freed to prevent memory leaks |
25 | 168k | gchar *id = poppler_structure_element_get_id(element); |
26 | 168k | g_free(id); |
27 | | |
28 | 168k | gchar *title = poppler_structure_element_get_title(element); |
29 | 168k | g_free(title); |
30 | | |
31 | 168k | gchar *language = poppler_structure_element_get_language(element); |
32 | 168k | g_free(language); |
33 | | |
34 | 168k | gchar *abbreviation = poppler_structure_element_get_abbreviation(element); |
35 | 168k | g_free(abbreviation); |
36 | | |
37 | 168k | gchar *alt_text = poppler_structure_element_get_alt_text(element); |
38 | 168k | g_free(alt_text); |
39 | | |
40 | 168k | gchar *actual_text = poppler_structure_element_get_actual_text(element); |
41 | 168k | g_free(actual_text); |
42 | | |
43 | | // Check if it's content and test text extraction |
44 | 168k | if (poppler_structure_element_is_content(element)) { |
45 | | // Test non-recursive mode |
46 | 109k | gchar *text = poppler_structure_element_get_text(element, POPPLER_STRUCTURE_GET_TEXT_NONE); |
47 | 109k | g_free(text); |
48 | | |
49 | | // Test recursive mode |
50 | 109k | text = poppler_structure_element_get_text(element, POPPLER_STRUCTURE_GET_TEXT_RECURSIVE); |
51 | 109k | g_free(text); |
52 | 109k | } |
53 | | |
54 | | // Recurse into children |
55 | 168k | PopplerStructureElementIter *child_iter = poppler_structure_element_iter_get_child(iter); |
56 | 168k | if (child_iter) { |
57 | 46.5k | exercise_structure_tree(child_iter); |
58 | 46.5k | poppler_structure_element_iter_free(child_iter); |
59 | 46.5k | } |
60 | | |
61 | 168k | g_object_unref(element); |
62 | | |
63 | 168k | } while (poppler_structure_element_iter_next(iter)); |
64 | 52.9k | } |
65 | | |
66 | | // Fuzzer entry point |
67 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
68 | 8.32k | { |
69 | 8.32k | GlobalParamsIniter globalParamsIniter(nullptr); |
70 | 8.32k | globalParams->setErrQuiet(true); |
71 | | |
72 | 8.32k | GError *err = NULL; |
73 | | |
74 | | // Load document from fuzzer input |
75 | 8.32k | GBytes *bytes = g_bytes_new_static(data, size); |
76 | 8.32k | PopplerDocument *doc = poppler_document_new_from_bytes(bytes, NULL, &err); |
77 | 8.32k | g_bytes_unref(bytes); |
78 | | |
79 | 8.32k | if (doc == NULL) { |
80 | 1.40k | if (err) { |
81 | 1.40k | g_error_free(err); |
82 | 1.40k | } |
83 | 1.40k | return 0; |
84 | 1.40k | } |
85 | | |
86 | | // Try to create iterator - if it fails, no structure tree exists |
87 | 6.92k | PopplerStructureElementIter *root_iter = poppler_structure_element_iter_new(doc); |
88 | 6.92k | if (root_iter) { |
89 | 6.31k | exercise_structure_tree(root_iter); |
90 | 6.31k | poppler_structure_element_iter_free(root_iter); |
91 | 6.31k | } |
92 | | |
93 | 6.92k | g_object_unref(doc); |
94 | 6.92k | return 0; |
95 | 8.32k | } |