/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  | }  |