Coverage Report

Created: 2026-06-10 06:30

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