lib/deadalloc/src/properties/exterminator.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const hypothesis = @import("hypothesis");
 3 const deadalloc = @import("deadalloc");
 4 
 5 const RepairPolicy = deadalloc.RepairPolicy;
 6 
 7 pub fn settings() hypothesis.Settings {
 8     return hypothesis.Settings.quick()
 9         .withSeed(0xde47_a110)
10         .withDatabase("zig-out/hypothesis-failures/deadalloc");
11 }
12 
13 fn drawPropertyUsize(conjecture: *hypothesis.ConjectureData, min: usize, max: usize, shrink_towards: usize) !usize {
14     return @intCast(try conjecture.drawInteger(
15         @intCast(min),
16         @intCast(max),
17         @intCast(shrink_towards),
18     ));
19 }
20 
21 pub const RepairPolicyProperty = struct {
22     pub fn property(conjecture: *hypothesis.ConjectureData, allocator: std.mem.Allocator) !void {
23         _ = allocator;
24 
25         const red_zone_bytes = try drawPropertyUsize(conjecture, 0, 2048, 16);
26         const quarantine_epochs: u64 = @intCast(try drawPropertyUsize(conjecture, 0, 8192, 16));
27         const buffer_overflow = try drawPropertyUsize(conjecture, 0, 1, 0);
28         const use_after_free = try drawPropertyUsize(conjecture, 0, 1, 0);
29         const double_free = try drawPropertyUsize(conjecture, 0, 1, 0);
30         const alloc_site = try drawPropertyUsize(conjecture, 1, 4096, 1);
31         const free_site = try drawPropertyUsize(conjecture, 4097, 8192, 4097);
32         const requested_len = try drawPropertyUsize(conjecture, 1, 256, 16);
33         const overflow_extra = try drawPropertyUsize(conjecture, 0, 64, 0);
34 
35         const current: RepairPolicy = .{
36             .red_zone_bytes = red_zone_bytes,
37             .quarantine_epochs = quarantine_epochs,
38         };
39         var report: deadalloc.Report = .{
40             .counters = .{
41                 .buffer_overflow = buffer_overflow,
42                 .use_after_free = use_after_free,
43                 .double_free = double_free,
44             },
45         };
46         if (buffer_overflow > 0) {
47             report.issues.append(.{
48                 .kind = .buffer_overflow,
49                 .offset = requested_len + overflow_extra,
50                 .requested_len = requested_len,
51                 .allocation_return_address = alloc_site,
52             });
53         }
54         if (use_after_free > 0 or double_free > 0) {
55             report.issues.append(.{
56                 .kind = if (use_after_free > 0) .use_after_free else .double_free,
57                 .allocation_return_address = alloc_site,
58                 .free_return_address = free_site,
59             });
60         }
61         const repaired = RepairPolicy.fromReport(report, current);
62 
63         if (buffer_overflow == 0) {
64             try std.testing.expectEqual(current.red_zone_bytes, repaired.red_zone_bytes);
65         } else if (current.red_zone_bytes == 0) {
66             try std.testing.expectEqual(@as(usize, 16), repaired.red_zone_bytes);
67         } else if (current.red_zone_bytes < 1024) {
68             try std.testing.expectEqual(@min(current.red_zone_bytes * 2, 1024), repaired.red_zone_bytes);
69         } else {
70             try std.testing.expectEqual(current.red_zone_bytes, repaired.red_zone_bytes);
71         }
72 
73         if (use_after_free == 0 and double_free == 0) {
74             try std.testing.expectEqual(current.quarantine_epochs, repaired.quarantine_epochs);
75         } else if (current.quarantine_epochs == 0) {
76             try std.testing.expectEqual(@as(u64, 1), repaired.quarantine_epochs);
77         } else if (current.quarantine_epochs < 4096) {
78             try std.testing.expectEqual(@min(current.quarantine_epochs * 2, 4096), repaired.quarantine_epochs);
79         } else {
80             try std.testing.expectEqual(current.quarantine_epochs, repaired.quarantine_epochs);
81         }
82 
83         if (buffer_overflow == 0) {
84             try std.testing.expectEqual(@as(usize, 0), repaired.repairs.overflowPadding(alloc_site));
85         } else {
86             try std.testing.expectEqual(overflow_extra + 1, repaired.repairs.overflowPadding(alloc_site));
87         }
88 
89         if (use_after_free == 0 and double_free == 0) {
90             try std.testing.expectEqual(@as(u64, 0), repaired.repairs.lifeExtension(alloc_site, free_site));
91         } else {
92             try std.testing.expectEqual(@as(u64, 1), repaired.repairs.lifeExtension(alloc_site, free_site));
93         }
94     }
95 };
96 
97 test "property: repair policy grows diagnostics monotonically" {
98     try hypothesis.checkNamed(RepairPolicyProperty, "deadalloc-repair-policy", settings());
99 }