summaryrefslogtreecommitdiff
path: root/bindgen-tests/tests/quickchecking/src/fuzzers.rs
blob: 003e9bf3f1e49e4d8bcc8171d8154a1a201d1155 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
use quickcheck::{Arbitrary, Gen};
use std::fmt;

/// BaseTypeC is used in generation of C headers to represent the C language's
/// primitive types as well as `void*`.
#[derive(Debug, Clone)]
pub struct BaseTypeC {
    /// String representation of C type.
    pub def: String,
}

/// TypeQualifierC is used in generation of C headers to represent qualifiers
/// such as `const`.
#[derive(Debug, Clone)]
pub struct TypeQualifierC {
    /// String representation of C type qualifier.
    pub def: String,
}

/// PointerLevelC is used in generation of C headers to represent number of
/// `*` for pointer types.
#[derive(Debug, Clone)]
pub struct PointerLevelC {
    /// String representation of C declaration's pointer level.
    pub def: String,
}

/// ArrayDimensionC is used in generation of C headers to represent number of
/// `[]` used to define array types.
#[derive(Debug, Clone)]
pub struct ArrayDimensionC {
    /// String representation of C declaration's array dimension.
    pub def: String,
}

/// BasicTypeDeclarationC is used in generation of C headers to represent
/// declarations outside of function pointers that take the form
/// `BaseTypeC` + `TypeQualifierC` + `PointerLevelC` + `ident_id`.
#[derive(Debug, Clone)]
pub struct BasicTypeDeclarationC {
    /// The declaration's base type, i.e. `int`.
    pub type_name: BaseTypeC,
    /// The declaration's type qualifier, i.e. `const`.
    pub type_qualifier: TypeQualifierC,
    /// The declaration's pointer level, i.e. `***`.
    pub pointer_level: PointerLevelC,
    /// The declaration's array dimension, i.e. [][][].
    pub array_dimension: ArrayDimensionC,
    /// The declaration's identifier, i.e. ident_N.
    pub ident_id: String,
}

/// StructDeclarationC is used in generation of C headers to represent the
/// definition of a struct type.
#[derive(Debug, Clone)]
pub struct StructDeclarationC {
    /// The declaration's fields.
    pub fields: DeclarationListC,
    /// The declaration's array dimension, i.e. [][][].
    pub array_dimension: ArrayDimensionC,
    /// The declaration's identifier, i.e. struct_N.
    pub ident_id: String,
}

/// UnionDeclarationC is used in generation of C headers to represent the
/// definition of a union type.
#[derive(Debug, Clone)]
pub struct UnionDeclarationC {
    /// The declaration's fields.
    pub fields: DeclarationListC,
    /// The declaration's array dimension, i.e. [][][].
    pub array_dimension: ArrayDimensionC,
    /// The declaration's identifier, i.e. union_N.
    pub ident_id: String,
}

/// FunctionPointerDeclarationC is used in generation of C headers to represent
/// the definition of a function pointer type.
#[derive(Debug, Clone)]
pub struct FunctionPointerDeclarationC {
    /// The function's type qualifier, i.e. `const`.
    pub type_qualifier: TypeQualifierC,
    /// The function's return type, i.e. `int`.
    pub type_name: BaseTypeC,
    /// The function's pointer level, i.e. `***`.
    pub pointer_level: PointerLevelC,
    /// The function's parameters.
    pub params: ParameterListC,
    /// The declaration's identifier, i.e. func_ptr_N.
    pub ident_id: String,
}

/// FunctionPrototypeC is used in generation of C headers to represent the
/// definition of a function prototype.
#[derive(Debug, Clone)]
pub struct FunctionPrototypeC {
    /// The function's type qualifier, i.e. `const`.
    pub type_qualifier: TypeQualifierC,
    /// The function's return type, i.e. `int`.
    pub type_name: BaseTypeC,
    /// The function's pointer level, i.e. `***`.
    pub pointer_level: PointerLevelC,
    /// The function's parameters.
    pub params: ParameterListC,
    /// The prototype's identifier, i.e. `func_N`.
    pub ident_id: String,
}

/// ParameterC is used in generation of C headers to represent the
/// definition function parameters.
#[derive(Debug, Clone)]
pub struct ParameterC {
    /// The parameter's type qualifier, i.e. `const`.
    pub type_qualifier: TypeQualifierC,
    /// The parameter's base type, i.e. `int`.
    pub type_name: BaseTypeC,
    /// The parameter's pointer level, i.e. `***`.
    pub pointer_level: PointerLevelC,
}

/// ParameterListC is used in generation of C headers to represent a list of
/// definitions of function parameters.
#[derive(Debug, Clone)]
pub struct ParameterListC {
    /// Parameters that define a C function signature.
    pub params: Vec<ParameterC>,
}

/// DeclarationC is used in generation of C headers to represent all supported
/// C type declarations allowed in the generated header.
#[derive(Debug, Clone)]
pub enum DeclarationC {
    /// Function prototype declaration kind.
    FunctionDecl(FunctionPrototypeC),
    /// Function pointer declaration kind.
    FunctionPtrDecl(FunctionPointerDeclarationC),
    /// Struct declaration kind.
    StructDecl(StructDeclarationC),
    /// Union declaration kind.
    UnionDecl(UnionDeclarationC),
    /// Basic type declaration kind.
    VariableDecl(BasicTypeDeclarationC),
}

/// DeclarationListC is used in generation of C headers to represent a list of
/// declarations.
#[derive(Debug, Clone)]
pub struct DeclarationListC {
    /// Grouping of C declarations.
    pub decls: Vec<DeclarationC>,
}

/// HeaderC is used in generation of C headers to represent a collection of
/// declarations.
#[derive(Clone)]
pub struct HeaderC {
    /// The header's declarations.
    pub def: DeclarationListC,
}

/// MakeUnique is used in generation of C headers to make declaration
/// identifiers unique by incorporating the `stamp` parameter into it's name.
trait MakeUnique {
    fn make_unique(&mut self, stamp: usize);
}

/// MakeUnique is used in generation of C headers to make DeclarationC
/// identifiers unique.
impl MakeUnique for DeclarationC {
    fn make_unique(&mut self, stamp: usize) {
        match *self {
            DeclarationC::FunctionDecl(ref mut d) => d.make_unique(stamp),
            DeclarationC::FunctionPtrDecl(ref mut d) => d.make_unique(stamp),
            DeclarationC::StructDecl(ref mut d) => d.make_unique(stamp),
            DeclarationC::UnionDecl(ref mut d) => d.make_unique(stamp),
            DeclarationC::VariableDecl(ref mut d) => d.make_unique(stamp),
        }
    }
}

/// A qucickcheck trait for describing how DeclarationC types can be
/// randomly generated and shrunk.
impl Arbitrary for DeclarationC {
    fn arbitrary(g: &mut Gen) -> DeclarationC {
        match gen_range(g, 0, 5) {
            0 => DeclarationC::FunctionDecl(FunctionPrototypeC::arbitrary(g)),
            1 => DeclarationC::FunctionPtrDecl(
                FunctionPointerDeclarationC::arbitrary(g),
            ),
            2 => DeclarationC::StructDecl(StructDeclarationC::arbitrary(g)),
            3 => DeclarationC::UnionDecl(UnionDeclarationC::arbitrary(g)),
            4 => {
                DeclarationC::VariableDecl(BasicTypeDeclarationC::arbitrary(g))
            }
            _ => unreachable!(),
        }
    }
}

/// Enables to string and format for DeclarationC types.
impl fmt::Display for DeclarationC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            DeclarationC::FunctionPtrDecl(ref d) => write!(f, "{}", d),
            DeclarationC::StructDecl(ref d) => write!(f, "{}", d),
            DeclarationC::UnionDecl(ref d) => write!(f, "{}", d),
            DeclarationC::VariableDecl(ref d) => write!(f, "{}", d),
            DeclarationC::FunctionDecl(ref d) => write!(f, "{}", d),
        }
    }
}

/// A qucickcheck trait for describing how DeclarationListC types can be
/// randomly generated and shrunk.
impl Arbitrary for DeclarationListC {
    fn arbitrary(g: &mut Gen) -> DeclarationListC {
        DeclarationListC {
            decls: Arbitrary::arbitrary(g),
        }
    }
}

/// Enables to string and format for DeclarationListC types.
impl fmt::Display for DeclarationListC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut display = String::new();
        for decl in &self.decls {
            display += &format!("{}", decl);
        }
        write!(f, "{}", display)
    }
}

/// A qucickcheck trait for describing how BaseTypeC types can be
/// randomly generated and shrunk.
impl Arbitrary for BaseTypeC {
    fn arbitrary(g: &mut Gen) -> BaseTypeC {
        // Special case `long double` until issue #550 is resolved.
        let base_type = vec![
            "char",
            "signed char",
            "unsigned char",
            "short",
            "short int",
            "signed short",
            "signed short int",
            "unsigned short",
            "unsigned short int",
            "int",
            "signed",
            "signed int",
            "unsigned",
            "unsigned int",
            "long",
            "long int",
            "signed long",
            "signed long int",
            "unsigned long",
            "unsigned long int",
            "long long",
            "long long int",
            "signed long long",
            "signed long long int",
            "unsigned long long",
            "unsigned long long int",
            "float",
            "double",
            #[cfg(feature = "long-doubles")]
            "long double",
            "void*",
        ];
        BaseTypeC {
            def: String::from(*g.choose(&base_type).unwrap()),
        }
    }
}

/// Enables to string and format for BaseTypeC types,
impl fmt::Display for BaseTypeC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.def)
    }
}

/// A qucickcheck trait for describing how TypeQualifierC types can be
/// randomly generated and shrunk.
impl Arbitrary for TypeQualifierC {
    fn arbitrary(g: &mut Gen) -> TypeQualifierC {
        let qualifier = vec!["const", ""];
        TypeQualifierC {
            def: String::from(*g.choose(&qualifier).unwrap()),
        }
    }
}

/// Enables to string and format for TypeQualifierC types.
impl fmt::Display for TypeQualifierC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.def)
    }
}

/// A qucickcheck trait for describing how PointerLevelC types can be
/// randomly generated and shrunk.
impl Arbitrary for PointerLevelC {
    fn arbitrary(g: &mut Gen) -> PointerLevelC {
        PointerLevelC {
            // 16 is an arbitrary "not too big" number for capping pointer level.
            def: (0..gen_range(g, 0, 16)).map(|_| "*").collect::<String>(),
        }
    }
}

/// Enables to string and format for PointerLevelC types.
impl fmt::Display for PointerLevelC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.def)
    }
}

/// A qucickcheck trait for describing how ArrayDimensionC types can be
/// randomly generated and shrunk.
impl Arbitrary for ArrayDimensionC {
    fn arbitrary(g: &mut Gen) -> ArrayDimensionC {
        // Keep these small, clang complains when they get too big.
        let dimensions = gen_range(g, 0, 5);
        let mut def = String::new();

        let lower_bound = u64::from(cfg!(feature = "zero-sized-arrays"));

        for _ in 1..dimensions {
            // 16 is an arbitrary "not too big" number for capping array size.
            def += &format!("[{}]", gen_range(g, lower_bound, 16));
        }
        ArrayDimensionC { def }
    }
}

/// Enables to string and format for ArrayDimensionC types.
impl fmt::Display for ArrayDimensionC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.def)
    }
}

/// MakeUnique is used in generation of C headers to make BasicTypeDeclarationC
/// identifiers unique.
impl MakeUnique for BasicTypeDeclarationC {
    fn make_unique(&mut self, stamp: usize) {
        self.ident_id += &format!("_{}", stamp);
    }
}

/// A qucickcheck trait for describing how BasicTypeDeclarationC types can be
/// randomly generated and shrunk.
impl Arbitrary for BasicTypeDeclarationC {
    fn arbitrary(g: &mut Gen) -> BasicTypeDeclarationC {
        BasicTypeDeclarationC {
            type_qualifier: Arbitrary::arbitrary(g),
            type_name: Arbitrary::arbitrary(g),
            pointer_level: Arbitrary::arbitrary(g),
            array_dimension: Arbitrary::arbitrary(g),
            ident_id: format!("{}", usize::arbitrary(g)),
        }
    }
}

/// Enables to string and format for BasicTypeDeclarationC types.
impl fmt::Display for BasicTypeDeclarationC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} {} {} ident_{}{};",
            self.type_qualifier,
            self.type_name,
            self.pointer_level,
            self.ident_id,
            self.array_dimension
        )
    }
}

/// MakeUnique is used in generation of C headers to make StructDeclarationC
/// identifiers unique.
impl MakeUnique for StructDeclarationC {
    fn make_unique(&mut self, stamp: usize) {
        self.ident_id += &format!("_{}", stamp);
    }
}

/// A qucickcheck trait for describing how StructDeclarationC types can be
/// randomly generated and shrunk.
impl Arbitrary for StructDeclarationC {
    fn arbitrary(g: &mut Gen) -> StructDeclarationC {
        // Reduce generator size as a method of putting a bound on recursion.
        // When size < 1 the empty list is generated.
        let reduced_size: usize = (g.size() / 2) + 1;
        let mut decl_list: DeclarationListC =
            Arbitrary::arbitrary(&mut Gen::new(reduced_size));
        let mut fields: DeclarationListC = DeclarationListC { decls: vec![] };

        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
            match *decl {
                DeclarationC::FunctionDecl(_) => {}
                ref mut decl => {
                    decl.make_unique(i);
                    fields.decls.push(decl.clone());
                }
            }
        }

        StructDeclarationC {
            fields,
            ident_id: format!("{}", usize::arbitrary(g)),
            array_dimension: Arbitrary::arbitrary(g),
        }
    }
}

/// Enables to string and format for StructDeclarationC types.
impl fmt::Display for StructDeclarationC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "struct {{ {} }} struct_{}{};",
            self.fields, self.ident_id, self.array_dimension
        )
    }
}

/// MakeUnique is used in generation of C headers to make UnionDeclarationC
/// identifiers unique.
impl MakeUnique for UnionDeclarationC {
    fn make_unique(&mut self, stamp: usize) {
        self.ident_id += &format!("_{}", stamp);
    }
}

/// A qucickcheck trait for describing how UnionDeclarationC types can be
/// randomly generated and shrunk.
impl Arbitrary for UnionDeclarationC {
    fn arbitrary(g: &mut Gen) -> UnionDeclarationC {
        // Reduce generator size as a method of putting a bound on recursion.
        // When size < 1 the empty list is generated.
        let reduced_size: usize = (g.size() / 2) + 1;
        let mut decl_list: DeclarationListC =
            Arbitrary::arbitrary(&mut Gen::new(reduced_size));
        let mut fields: DeclarationListC = DeclarationListC { decls: vec![] };

        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
            match *decl {
                DeclarationC::FunctionDecl(_) => {}
                ref mut decl => {
                    decl.make_unique(i);
                    fields.decls.push(decl.clone());
                }
            }
        }

        UnionDeclarationC {
            fields,
            ident_id: format!("{}", usize::arbitrary(g)),
            array_dimension: Arbitrary::arbitrary(g),
        }
    }
}

/// Enables to string and format for UnionDeclarationC types.
impl fmt::Display for UnionDeclarationC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "union {{ {} }} union_{}{};",
            self.fields, self.ident_id, self.array_dimension
        )
    }
}

/// MakeUnique is used in generation of C headers to make
/// FunctionPointerDeclarationC identifiers unique.
impl MakeUnique for FunctionPointerDeclarationC {
    fn make_unique(&mut self, stamp: usize) {
        self.ident_id += &format!("_{}", stamp);
    }
}

/// A qucickcheck trait for describing how FunctionPointerDeclarationC types can
/// be randomly generated and shrunk.
impl Arbitrary for FunctionPointerDeclarationC {
    fn arbitrary(g: &mut Gen) -> FunctionPointerDeclarationC {
        FunctionPointerDeclarationC {
            type_qualifier: Arbitrary::arbitrary(g),
            type_name: Arbitrary::arbitrary(g),
            pointer_level: Arbitrary::arbitrary(g),
            params: Arbitrary::arbitrary(g),
            ident_id: format!("{}", usize::arbitrary(g)),
        }
    }
}

/// Enables to string and format for FunctionPointerDeclarationC types.
impl fmt::Display for FunctionPointerDeclarationC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} {} {} (*func_ptr_{})({});",
            self.type_qualifier,
            self.type_name,
            self.pointer_level,
            self.ident_id,
            self.params
        )
    }
}

/// MakeUnique is used in generation of C headers to make FunctionPrototypeC
/// identifiers unique.
impl MakeUnique for FunctionPrototypeC {
    fn make_unique(&mut self, stamp: usize) {
        self.ident_id += &format!("_{}", stamp);
    }
}

/// A qucickcheck trait for describing how FunctionPrototypeC types can be
/// randomly generated and shrunk.
impl Arbitrary for FunctionPrototypeC {
    fn arbitrary(g: &mut Gen) -> FunctionPrototypeC {
        FunctionPrototypeC {
            type_qualifier: Arbitrary::arbitrary(g),
            type_name: Arbitrary::arbitrary(g),
            pointer_level: Arbitrary::arbitrary(g),
            params: Arbitrary::arbitrary(g),
            ident_id: format!("{}", usize::arbitrary(g)),
        }
    }
}

/// Enables to string and format for FunctionPrototypeC types.
impl fmt::Display for FunctionPrototypeC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} {} {} func_{}({});",
            self.type_qualifier,
            self.type_name,
            self.pointer_level,
            self.ident_id,
            self.params
        )
    }
}

/// A qucickcheck trait for describing how ParameterC types can be
/// randomly generated and shrunk.
impl Arbitrary for ParameterC {
    fn arbitrary(g: &mut Gen) -> ParameterC {
        ParameterC {
            type_qualifier: Arbitrary::arbitrary(g),
            type_name: Arbitrary::arbitrary(g),
            pointer_level: Arbitrary::arbitrary(g),
        }
    }
}

/// Enables to string and format for ParameterC types.
impl fmt::Display for ParameterC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} {} {}",
            self.type_qualifier, self.type_name, self.pointer_level
        )
    }
}

/// A qucickcheck trait for describing how ParameterListC types can be
/// randomly generated and shrunk.
impl Arbitrary for ParameterListC {
    fn arbitrary(g: &mut Gen) -> ParameterListC {
        ParameterListC {
            params: Arbitrary::arbitrary(g),
        }
    }
}

/// Enables to string and format for ParameterListC types.
impl fmt::Display for ParameterListC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut display = String::new();
        for (i, p) in self.params.iter().enumerate() {
            match i {
                0 => display += &format!("{}", p),
                _ => display += &format!(",{}", p),
            }
        }
        write!(f, "{}", display)
    }
}

/// A qucickcheck trait for describing how HeaderC types can be
/// randomly generated and shrunk.
impl Arbitrary for HeaderC {
    fn arbitrary(g: &mut Gen) -> HeaderC {
        let mut decl_list: DeclarationListC = Arbitrary::arbitrary(g);
        for (i, decl) in decl_list.decls.iter_mut().enumerate() {
            decl.make_unique(i);
        }
        HeaderC { def: decl_list }
    }
}

/// Enables to string and format for HeaderC types.
impl fmt::Display for HeaderC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut display = String::new();
        for decl in &self.def.decls {
            display += &format!("{}", decl);
        }
        write!(f, "{}", display)
    }
}

/// Use Display trait for Debug so that any failing property tests report
/// generated C code rather than the data structures that contain it.
impl fmt::Debug for HeaderC {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self)
    }
}

/// FIXME: is this actually uniform?
fn gen_range(gen: &mut Gen, lo: u64, hi: u64) -> u64 {
    let len = hi - lo;
    (u64::arbitrary(gen) % len) + lo
}