Coverage Report

Created: 2025-07-01 07:02

/src/igraph/fuzzing/write_all_gml.cpp
Line
Count
Source (jump to first uncovered line)
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.0k
    do { \
30
53.0k
        igraph_error_handler_t *handler = igraph_set_error_handler(igraph_error_handler_abort); \
31
53.0k
        expr; \
32
53.0k
        igraph_set_error_handler(handler); \
33
53.0k
    } while (0)
34
35
extern "C"
36
26.7k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
37
38
26.7k
    igraph_set_error_handler(igraph_error_handler_ignore);
39
26.7k
    igraph_set_warning_handler(igraph_warning_handler_ignore);
40
41
    // Turn on attribute handling
42
26.7k
    igraph_set_attribute_table(&igraph_cattribute_table);
43
44
    // Read input file
45
26.7k
    FILE *ifile = fmemopen((void*) data, size, "r");
46
26.7k
    if (!ifile) {
47
0
        return 0;
48
0
    }
49
50
    // Do the fuzzing
51
26.7k
    igraph_t g;
52
26.7k
    if (igraph_read_graph_gml(&g, ifile) == IGRAPH_SUCCESS) {
53
8.93k
        FILE *file;
54
8.93k
        igraph_t g2;
55
56
8.93k
        file = tmpfile();
57
8.93k
        IGRAPH_ASSERT(file != NULL);
58
        // Do not check error because:
59
        // "Vertex attribute values cannot contain newline characters."
60
8.93k
        igraph_write_graph_leda(&g, file, "label", "weight");
61
8.93k
        fclose(file);
62
63
8.93k
        file = tmpfile();
64
8.93k
        IGRAPH_ASSERT(file != NULL);
65
8.93k
        CHECK_ERR(igraph_write_graph_dot(&g, file));
66
8.93k
        fclose(file);
67
68
8.93k
        file = tmpfile();
69
8.93k
        IGRAPH_ASSERT(file != NULL);
70
8.93k
        CHECK_ERR(igraph_write_graph_gml(&g, file, IGRAPH_WRITE_GML_DEFAULT_SW, NULL, "no one"));
71
8.93k
        rewind(file);
72
8.93k
        CHECK_ERR(igraph_read_graph_gml(&g2, file));
73
8.93k
        igraph_destroy(&g2);
74
8.93k
        fclose(file);
75
76
        // Reading Pajek files back is disabled because of
77
        // https://github.com/igraph/igraph/issues/2560
78
8.93k
        file = tmpfile();
79
8.93k
        IGRAPH_ASSERT(file != NULL);
80
8.93k
        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
8.93k
        fclose(file);
87
88
8.93k
        file = tmpfile();
89
8.93k
        IGRAPH_ASSERT(file != NULL);
90
        // Do not check error when writing GraphML because string attributes
91
        // may contain forbidden control characters.
92
8.93k
        if (igraph_write_graph_graphml(&g, file, false) == IGRAPH_SUCCESS) {
93
8.62k
            rewind(file);
94
            // Do not check error when reading because strings may not be
95
            // in a valid encoding, which confuses libxml2.
96
8.62k
            if (igraph_read_graph_graphml(&g2, file, 0) == IGRAPH_SUCCESS) {
97
7.56k
                igraph_destroy(&g2);
98
7.56k
            }
99
8.62k
        }
100
8.93k
        fclose(file);
101
102
8.93k
        file = tmpfile();
103
8.93k
        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
8.93k
        if (igraph_write_graph_lgl(&g, file, "label", "weight", false) == IGRAPH_SUCCESS) {
107
8.62k
            rewind(file);
108
8.62k
            CHECK_ERR(igraph_read_graph_lgl(&g2, file, true, IGRAPH_ADD_WEIGHTS_IF_PRESENT, true));
109
8.62k
            igraph_destroy(&g2);
110
8.62k
        }
111
8.93k
        fclose(file);
112
113
8.93k
        file = tmpfile();
114
8.93k
        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
8.93k
        if (igraph_write_graph_ncol(&g, file, "label", "weight") == IGRAPH_SUCCESS) {
118
8.68k
            rewind(file);
119
8.68k
            CHECK_ERR(igraph_read_graph_ncol(&g2, file, NULL, true, IGRAPH_ADD_WEIGHTS_IF_PRESENT, true));
120
8.68k
            igraph_destroy(&g2);
121
8.68k
        }
122
8.93k
        fclose(file);
123
124
        // Clean up
125
8.93k
        igraph_destroy(&g);
126
8.93k
    }
127
128
    // no need to call igraph_destroy() if igraph_read_graph_gml() returns an
129
    // error code as we don't have a valid graph object in that case
130
131
26.7k
    fclose(ifile);
132
133
26.7k
    IGRAPH_ASSERT(IGRAPH_FINALLY_STACK_EMPTY);
134
135
26.7k
    return 0;
136
26.7k
}