Coverage Report

Created: 2025-11-21 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/igraph/fuzzing/write_all_graphml.cpp
Line
Count
Source
1
/*
2
   igraph library.
3
   Copyright (C) 2024  The igraph development team
4
5
   This program is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 2 of the License, or
8
   (at your option) any later version.
9
10
   This program is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU General Public License for more details.
14
15
   You should have received a copy of the GNU General Public License
16
   along with this program; if not, write to the Free Software
17
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
   02110-1301 USA
19
*/
20
21
#include <igraph.h>
22
#include <cstdio>
23
24
// This fuzzer checks two things:
25
//  - Test writers for formats that igraph can only write but not read
26
//  - Test that files that igraph writes can be read back
27
28
#define CHECK_ERR(expr) \
29
53.9k
    do { \
30
53.9k
        igraph_error_handler_t *handler = igraph_set_error_handler(igraph_error_handler_abort); \
31
53.9k
        expr; \
32
53.9k
        igraph_set_error_handler(handler); \
33
53.9k
    } while (0)
34
35
extern "C"
36
26.9k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
37
38
26.9k
    igraph_set_error_handler(igraph_error_handler_ignore);
39
26.9k
    igraph_set_warning_handler(igraph_warning_handler_ignore);
40
41
    // Turn on attribute handling
42
26.9k
    igraph_set_attribute_table(&igraph_cattribute_table);
43
44
    // Read input file
45
26.9k
    FILE *ifile = fmemopen((void*) data, size, "r");
46
26.9k
    if (!ifile) {
47
0
        return 0;
48
0
    }
49
50
    // Do the fuzzing
51
26.9k
    igraph_t g;
52
26.9k
    if (igraph_read_graph_graphml(&g, ifile, 0) == IGRAPH_SUCCESS) {
53
9.08k
        FILE *file;
54
9.08k
        igraph_t g2;
55
56
9.08k
        file = tmpfile();
57
9.08k
        IGRAPH_ASSERT(file != NULL);
58
        // Do not check error because:
59
        // "Vertex attribute values cannot contain newline characters."
60
9.08k
        igraph_write_graph_leda(&g, file, "label", "weight");
61
9.08k
        fclose(file);
62
63
9.08k
        file = tmpfile();
64
9.08k
        IGRAPH_ASSERT(file != NULL);
65
9.08k
        CHECK_ERR(igraph_write_graph_dot(&g, file));
66
9.08k
        fclose(file);
67
68
9.08k
        file = tmpfile();
69
9.08k
        IGRAPH_ASSERT(file != NULL);
70
9.08k
        CHECK_ERR(igraph_write_graph_gml(&g, file, IGRAPH_WRITE_GML_DEFAULT_SW, NULL, "no one"));
71
9.08k
        rewind(file);
72
9.08k
        CHECK_ERR(igraph_read_graph_gml(&g2, file));
73
9.08k
        igraph_destroy(&g2);
74
9.08k
        fclose(file);
75
76
        // Reading Pajek files back is disabled because of
77
        // https://github.com/igraph/igraph/issues/2560
78
9.08k
        file = tmpfile();
79
9.08k
        IGRAPH_ASSERT(file != NULL);
80
9.08k
        CHECK_ERR(igraph_write_graph_pajek(&g, file));
81
        /*
82
        rewind(file);
83
        CHECK_ERR(igraph_read_graph_pajek(&g2, file));
84
        igraph_destroy(&g2);
85
        */
86
9.08k
        fclose(file);
87
88
9.08k
        file = tmpfile();
89
9.08k
        IGRAPH_ASSERT(file != NULL);
90
        // Do not check error when writing GraphML because string attributes
91
        // may contain forbidden control characters.
92
9.08k
        if (igraph_write_graph_graphml(&g, file, false) == IGRAPH_SUCCESS) {
93
8.77k
            rewind(file);
94
            // Do not check error when reading because strings may not be
95
            // in a valid encoding, which confuses libxml2.
96
8.77k
            if (igraph_read_graph_graphml(&g2, file, 0) == IGRAPH_SUCCESS) {
97
7.74k
                igraph_destroy(&g2);
98
7.74k
            }
99
8.77k
        }
100
9.08k
        fclose(file);
101
102
9.08k
        file = tmpfile();
103
9.08k
        IGRAPH_ASSERT(file != NULL);
104
        // Do not check error when writing LGL because not all possible
105
        // vertex names are supported by this format.
106
9.08k
        if (igraph_write_graph_lgl(&g, file, "label", "weight", false) == IGRAPH_SUCCESS) {
107
8.77k
            rewind(file);
108
8.77k
            CHECK_ERR(igraph_read_graph_lgl(&g2, file, true, IGRAPH_ADD_WEIGHTS_IF_PRESENT, true));
109
8.77k
            igraph_destroy(&g2);
110
8.77k
        }
111
9.08k
        fclose(file);
112
113
9.08k
        file = tmpfile();
114
9.08k
        IGRAPH_ASSERT(file != NULL);
115
        // Do not check error when writing NCOL because not all possible
116
        // vertex names are supported by this format.
117
9.08k
        if (igraph_write_graph_ncol(&g, file, "label", "weight") == IGRAPH_SUCCESS) {
118
8.85k
            rewind(file);
119
8.85k
            CHECK_ERR(igraph_read_graph_ncol(&g2, file, NULL, true, IGRAPH_ADD_WEIGHTS_IF_PRESENT, true));
120
8.85k
            igraph_destroy(&g2);
121
8.85k
        }
122
9.08k
        fclose(file);
123
124
        // Clean up
125
9.08k
        igraph_destroy(&g);
126
9.08k
    }
127
128
    // no need to call igraph_destroy() if igraph_read_graph_graphml() returns an
129
    // error code as we don't have a valid graph object in that case
130
131
26.9k
    fclose(ifile);
132
133
26.9k
    IGRAPH_ASSERT(IGRAPH_FINALLY_STACK_EMPTY);
134
135
26.9k
    return 0;
136
26.9k
}