1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/types.h>
5 #include <sndfile.h>
6 #include <inttypes.h>
7
8 typedef struct
9 {
10 sf_count_t offset;
11 sf_count_t length;
12 const unsigned char *data;
13 } VIO_DATA;
14
vfget_filelen(void * user_data)15 static sf_count_t vfget_filelen (void *user_data)
16 {
17 VIO_DATA *vf = (VIO_DATA *)user_data;
18 return vf->length;
19 }
20
vfseek(sf_count_t offset,int whence,void * user_data)21 static sf_count_t vfseek (sf_count_t offset, int whence, void *user_data)
22 {
23 VIO_DATA *vf = (VIO_DATA *)user_data;
24 sf_count_t new_offset;
25
26 switch (whence)
27 {
28 case SEEK_SET:
29 new_offset = offset;
30 break ;
31
32 case SEEK_CUR:
33 new_offset = vf->offset + offset;
34 break ;
35
36 case SEEK_END:
37 new_offset = vf->length + offset;
38 break;
39
40 default:
41 break;
42 }
43
44 /* Ensure you can't seek outside the data */
45 if (new_offset > vf->length)
46 {
47 /* Trying to seek past the end of the data */
48 printf("vf overseek: new_offset(%" PRId64 ") > vf->length(%" PRId64 ");"
49 " whence(%d), vf->offset(%" PRId64 "), offset(%" PRId64 ")\n",
50 new_offset, vf->length, whence, vf->offset, offset);
51 new_offset = vf->length;
52 }
53 else if (new_offset < 0)
54 {
55 /* Trying to seek before the start of the data */
56 printf("vf underseek: new_offset(%" PRId64 ") < 0; whence(%d), vf->offset"
57 "(%" PRId64 "), vf->length(%" PRId64 "), offset(%" PRId64 ")\n",
58 new_offset, whence, vf->offset, vf->length, offset);
59 new_offset = 0;
60 }
61 vf->offset = new_offset;
62
63 return vf->offset;
64 }
65
vfread(void * ptr,sf_count_t count,void * user_data)66 static sf_count_t vfread (void *ptr, sf_count_t count, void *user_data)
67 {
68 VIO_DATA *vf = (VIO_DATA *)user_data;
69
70 if (vf->offset + count > vf->length)
71 {
72 count = vf->length - vf->offset;
73 }
74
75 memcpy(ptr, vf->data + vf->offset, count);
76 vf->offset += count;
77
78 return count;
79 }
80
vfwrite(const void * ptr,sf_count_t count,void * user_data)81 static sf_count_t vfwrite (const void *ptr, sf_count_t count, void *user_data)
82 {
83 (void)ptr;
84 (void)count;
85 (void)user_data;
86
87 // Cannot write to this virtual file.
88 return 0;
89 }
90
vftell(void * user_data)91 static sf_count_t vftell (void *user_data)
92 { VIO_DATA *vf = (VIO_DATA *)user_data;
93
94 return vf->offset;
95 }
96
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)97 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
98 {
99 VIO_DATA vio_data;
100 SF_VIRTUAL_IO vio;
101 SF_INFO sndfile_info;
102 SNDFILE *sndfile = NULL;
103 float* read_buffer = NULL;
104
105 // Initialize the virtual IO structure.
106 vio.get_filelen = vfget_filelen;
107 vio.seek = vfseek;
108 vio.read = vfread;
109 vio.write = vfwrite;
110 vio.tell = vftell;
111
112 // Initialize the VIO user data.
113 vio_data.data = data;
114 vio_data.length = size;
115 vio_data.offset = 0;
116
117 memset(&sndfile_info, 0, sizeof(SF_INFO));
118
119 // Try and open the virtual file.
120 sndfile = sf_open_virtual(&vio, SFM_READ, &sndfile_info, &vio_data);
121
122 if (sndfile_info.channels == 0)
123 {
124 // No sound channels in file.
125 goto EXIT_LABEL;
126 }
127 else if (sndfile_info.channels > 1024 * 1024)
128 {
129 // Too many channels to handle.
130 goto EXIT_LABEL;
131 }
132
133 // Just the right number of channels. Create some buffer space for reading.
134 read_buffer = (float*)malloc(sizeof(float) * sndfile_info.channels);
135 if (read_buffer == NULL)
136 {
137 abort();
138 }
139
140 while (sf_readf_float(sndfile, read_buffer, 1))
141 {
142 // Do nothing with the data.
143 }
144
145 EXIT_LABEL:
146
147 if (sndfile != NULL)
148 {
149 sf_close(sndfile);
150 }
151
152 free(read_buffer);
153
154 return 0;
155 }
156