Coverage Report

Created: 2024-02-25 06:34

/src/htslib/test/fuzz/hts_open_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
/*  test/fuzz/hts_open_fuzzer.c -- Fuzz driver for hts_open.
2
3
    Copyright (C) 2018 Google LLC.
4
    Copyright (C) 2019-2020, 2023 Genome Research Ltd.
5
6
    Author: Markus Kusano <kusano@google.com>
7
8
Permission is hereby granted, free of charge, to any person obtaining a copy
9
of this software and associated documentation files (the "Software"), to deal
10
in the Software without restriction, including without limitation the rights
11
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
copies of the Software, and to permit persons to whom the Software is
13
furnished to do so, subject to the following conditions:
14
15
The above copyright notice and this permission notice shall be included in
16
all copies or substantial portions of the Software.
17
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
DEALINGS IN THE SOFTWARE.  */
25
26
#include <config.h>
27
28
#include <stddef.h>
29
#include <stdint.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
#include <unistd.h>
34
35
#include "../../htslib/hfile.h"
36
#include "../../htslib/hts.h"
37
#include "../../htslib/sam.h"
38
#include "../../htslib/vcf.h"
39
40
14.4k
static void hts_close_or_abort(htsFile* file) {
41
14.4k
    if (hts_close(file) != 0) {
42
0
        abort();
43
0
    }
44
14.4k
}
45
46
static void view_sam(const uint8_t *data, size_t size, char *mode,
47
13.1k
                     int close_abort) {
48
13.1k
    uint8_t *copy = malloc(size);
49
13.1k
    if (copy == NULL) {
50
0
        abort();
51
0
    }
52
13.1k
    memcpy(copy, data, size);
53
54
13.1k
    hFILE *memfile = hopen("mem:", "rb:", copy, size);
55
13.1k
    if (memfile == NULL) {
56
0
        free(copy);
57
0
        return;
58
0
    }
59
60
13.1k
    htsFile *in = hts_hopen(memfile, "data", "rb");
61
13.1k
    if (in == NULL) {
62
0
        if (hclose(memfile) != 0)
63
0
            abort();
64
0
        return;
65
0
    }
66
67
13.1k
    samFile *out = sam_open("/dev/null", mode);
68
13.1k
    if (!out)
69
0
        abort();
70
71
#ifdef FUZZ_FAI
72
    // Not critical if this doesn't work, but can test more if
73
    // we're in the right location.
74
    //
75
    // We can't rely on what the pwd is for the OSS-fuzz so we don't enable
76
    // this by default.
77
    if (hts_set_fai_filename(out, "../c2.fa") < 0) {
78
        static int warned = 0;
79
        if (!warned) {
80
            warned = 1;
81
            fprintf(stderr, "Warning couldn't find the c2.fa file\n");
82
        }
83
    }
84
#endif
85
86
13.1k
    sam_hdr_t *hdr = sam_hdr_read(in);
87
13.1k
    if (hdr == NULL) {
88
240
        if (close_abort)
89
160
            hts_close_or_abort(out);
90
80
        else
91
80
            hts_close(out);
92
240
        hts_close(in);
93
240
        return;
94
240
    }
95
96
    // This will force the header to be parsed.
97
12.9k
    (void) sam_hdr_count_lines(hdr, "SQ");
98
99
12.9k
    if (sam_hdr_write(out, hdr) != 0)
100
332
        goto err;
101
102
12.6k
    bam1_t *b = bam_init1();
103
12.6k
    if (b == NULL)
104
0
        goto err;
105
106
27.7M
    while (sam_read1(in, hdr, b) >= 0) {
107
27.7M
        if (sam_write1(out, hdr, b) < 0)
108
585
            break;
109
27.7M
    }
110
12.6k
    bam_destroy1(b);
111
112
12.9k
 err:
113
12.9k
    sam_hdr_destroy(hdr);
114
12.9k
    if (close_abort)
115
8.63k
        hts_close_or_abort(out);
116
4.31k
    else
117
4.31k
        hts_close(out);
118
12.9k
    hts_close(in);
119
12.9k
}
120
121
5.64k
static void view_vcf(const uint8_t *data, size_t size, char *mode) {
122
5.64k
    uint8_t *copy = malloc(size);
123
5.64k
    if (copy == NULL) {
124
0
        abort();
125
0
    }
126
5.64k
    memcpy(copy, data, size);
127
128
5.64k
    hFILE *memfile = hopen("mem:", "rb:", copy, size);
129
5.64k
    if (memfile == NULL) {
130
0
        free(copy);
131
0
        return;
132
0
    }
133
134
5.64k
    htsFile *in = hts_hopen(memfile, "data", "rb");
135
5.64k
    if (in == NULL) {
136
0
        if (hclose(memfile) != 0)
137
0
            abort();
138
0
        return;
139
0
    }
140
141
5.64k
    vcfFile *out = vcf_open("/dev/null", mode);
142
5.64k
    if (!out)
143
0
        abort();
144
145
5.64k
    bcf_hdr_t *hdr = bcf_hdr_read(in);
146
5.64k
    if (hdr == NULL) {
147
880
        hts_close_or_abort(out);
148
880
        hts_close(in);
149
880
        return;
150
880
    }
151
152
4.76k
    if (bcf_hdr_write(out, hdr) != 0)
153
0
        goto err;
154
155
4.76k
    bcf1_t *rec = bcf_init();
156
4.76k
    if (rec == NULL)
157
0
        goto err;
158
159
22.7k
    while (bcf_read(in, hdr, rec) >= 0) {
160
20.0k
        if (bcf_write(out, hdr, rec) < 0)
161
2.04k
            break;
162
20.0k
    }
163
4.76k
    bcf_destroy(rec);
164
165
4.76k
 err:
166
4.76k
    bcf_hdr_destroy(hdr);
167
4.76k
    hts_close_or_abort(out);
168
4.76k
    hts_close(in);
169
4.76k
}
170
171
7.76k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
172
    // Only data as a mem file purely for purposes of determining format
173
7.76k
    hFILE *memfile;
174
7.76k
    uint8_t *copy = malloc(size);
175
7.76k
    if (copy == NULL) {
176
0
        abort();
177
0
    }
178
7.76k
    memcpy(copy, data, size);
179
    // hopen does not take ownership of `copy`, but hts_hopen does.
180
7.76k
    memfile = hopen("mem:", "rb:", copy, size);
181
7.76k
    if (memfile == NULL) {
182
0
        free(copy);
183
0
        return 0;
184
0
    }
185
186
7.76k
    htsFile *ht_file = hts_hopen(memfile, "data", "rb");
187
7.76k
    if (ht_file == NULL) {
188
545
        if (hclose(memfile) != 0) {
189
0
            abort();
190
0
        }
191
545
        return 0;
192
545
    }
193
7.22k
    int ftype = ht_file->format.category;
194
7.22k
    hts_close(ht_file);
195
196
    // Now repeat a read-write loop multiple times per input, testing
197
    // encoding in all output formats.
198
    // (Although we could just ignore ftype and do all 5 for all inputs)
199
7.22k
    switch (ftype) {
200
4.39k
        case sequence_data:
201
4.39k
            view_sam(data, size, "w",  1); // SAM
202
4.39k
            view_sam(data, size, "wb", 1); // BAM
203
4.39k
            view_sam(data, size, "wc", 0); // CRAM
204
4.39k
            break;
205
2.82k
        case variant_data:
206
2.82k
            view_vcf(data, size, "w");     // VCF
207
2.82k
            view_vcf(data, size, "wb");    // BCF
208
2.82k
            break;
209
5
        default:
210
5
            break;
211
7.22k
    }
212
7.22k
    return 0;
213
7.22k
}