Coverage Report

Created: 2026-01-10 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/htslib/test/fuzz/hts_open_fuzzer.c
Line
Count
Source
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
8.84k
static void hts_close_or_abort(htsFile* file) {
41
8.84k
    if (hts_close(file) != 0) {
42
0
        abort();
43
0
    }
44
8.84k
}
45
46
static void view_sam(const uint8_t *data, size_t size, char *mode,
47
8.61k
                     int close_abort) {
48
8.61k
    uint8_t *copy = malloc(size);
49
8.61k
    if (copy == NULL) {
50
0
        abort();
51
0
    }
52
8.61k
    memcpy(copy, data, size);
53
54
8.61k
    hFILE *memfile = hopen("mem:", "rb:", copy, size);
55
8.61k
    if (memfile == NULL) {
56
0
        free(copy);
57
0
        return;
58
0
    }
59
60
8.61k
    htsFile *in = hts_hopen(memfile, "data", "rb");
61
8.61k
    if (in == NULL) {
62
0
        if (hclose(memfile) != 0)
63
0
            abort();
64
0
        return;
65
0
    }
66
67
8.61k
    samFile *out = sam_open("/dev/null", mode);
68
8.61k
    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
8.61k
    sam_hdr_t *hdr = sam_hdr_read(in);
87
8.61k
    if (hdr == NULL) {
88
426
        if (close_abort)
89
284
            hts_close_or_abort(out);
90
142
        else
91
142
            hts_close(out);
92
426
        hts_close(in);
93
426
        return;
94
426
    }
95
96
    // This will force the header to be parsed.
97
8.18k
    (void) sam_hdr_count_lines(hdr, "SQ");
98
99
8.18k
    if (sam_hdr_write(out, hdr) != 0)
100
118
        goto err;
101
102
8.06k
    bam1_t *b = bam_init1();
103
8.06k
    if (b == NULL)
104
0
        goto err;
105
106
30.6M
    while (sam_read1(in, hdr, b) >= 0) {
107
30.6M
        if (sam_write1(out, hdr, b) < 0)
108
170
            break;
109
30.6M
    }
110
8.06k
    bam_destroy1(b);
111
112
8.18k
 err:
113
8.18k
    sam_hdr_destroy(hdr);
114
8.18k
    if (close_abort)
115
5.45k
        hts_close_or_abort(out);
116
2.72k
    else
117
2.72k
        hts_close(out);
118
8.18k
    hts_close(in);
119
8.18k
}
120
121
3.10k
static void view_vcf(const uint8_t *data, size_t size, char *mode) {
122
3.10k
    uint8_t *copy = malloc(size);
123
3.10k
    if (copy == NULL) {
124
0
        abort();
125
0
    }
126
3.10k
    memcpy(copy, data, size);
127
128
3.10k
    hFILE *memfile = hopen("mem:", "rb:", copy, size);
129
3.10k
    if (memfile == NULL) {
130
0
        free(copy);
131
0
        return;
132
0
    }
133
134
3.10k
    htsFile *in = hts_hopen(memfile, "data", "rb");
135
3.10k
    if (in == NULL) {
136
0
        if (hclose(memfile) != 0)
137
0
            abort();
138
0
        return;
139
0
    }
140
141
3.10k
    vcfFile *out = vcf_open("/dev/null", mode);
142
3.10k
    if (!out)
143
0
        abort();
144
145
3.10k
    bcf_hdr_t *hdr = bcf_hdr_read(in);
146
3.10k
    if (hdr == NULL) {
147
462
        hts_close_or_abort(out);
148
462
        hts_close(in);
149
462
        return;
150
462
    }
151
152
2.63k
    if (bcf_hdr_write(out, hdr) != 0)
153
0
        goto err;
154
155
2.63k
    bcf1_t *rec = bcf_init();
156
2.63k
    if (rec == NULL)
157
0
        goto err;
158
159
52.1k
    while (bcf_read(in, hdr, rec) >= 0) {
160
50.6k
        if (bcf_write(out, hdr, rec) < 0)
161
1.15k
            break;
162
50.6k
    }
163
2.63k
    bcf_destroy(rec);
164
165
2.63k
 err:
166
2.63k
    bcf_hdr_destroy(hdr);
167
2.63k
    hts_close_or_abort(out);
168
2.63k
    hts_close(in);
169
2.63k
}
170
171
4.46k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
172
    // Only data as a mem file purely for purposes of determining format
173
4.46k
    hFILE *memfile;
174
4.46k
    uint8_t *copy = malloc(size);
175
4.46k
    if (copy == NULL) {
176
0
        abort();
177
0
    }
178
4.46k
    memcpy(copy, data, size);
179
    // hopen does not take ownership of `copy`, but hts_hopen does.
180
4.46k
    memfile = hopen("mem:", "rb:", copy, size);
181
4.46k
    if (memfile == NULL) {
182
0
        free(copy);
183
0
        return 0;
184
0
    }
185
186
4.46k
    htsFile *ht_file = hts_hopen(memfile, "data", "rb");
187
4.46k
    if (ht_file == NULL) {
188
48
        if (hclose(memfile) != 0) {
189
0
            abort();
190
0
        }
191
48
        return 0;
192
48
    }
193
4.42k
    int ftype = ht_file->format.category;
194
4.42k
    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
4.42k
    switch (ftype) {
200
2.87k
        case sequence_data:
201
2.87k
            view_sam(data, size, "w",  1); // SAM
202
2.87k
            view_sam(data, size, "wb", 1); // BAM
203
2.87k
            view_sam(data, size, "wc", 0); // CRAM
204
2.87k
            break;
205
1.55k
        case variant_data:
206
1.55k
            view_vcf(data, size, "w");     // VCF
207
1.55k
            view_vcf(data, size, "wb");    // BCF
208
1.55k
            break;
209
1
        default:
210
1
            break;
211
4.42k
    }
212
4.42k
    return 0;
213
4.42k
}