| ... | @@ -57,9 +57,6 @@ fn bitsetUsizes(elems: usize) usize { | ... | @@ -57,9 +57,6 @@ fn bitsetUsizes(elems: usize) usize { |
| 57 | const Executable = struct { | 57 | const Executable = struct { |
| 58 | /// Tracks the hit count for each pc as updated by the process's instrumentation. | 58 | /// Tracks the hit count for each pc as updated by the process's instrumentation. |
| 59 | pc_counters: []u8, | 59 | pc_counters: []u8, |
| 60 | /// Read-only memory section containing compiled-in constants found from parsing the executable | | |
| 61 | rodata_addr: usize, | | |
| 62 | rodata_size: usize, | | |
| 63 | | 60 | |
| 64 | cache_f: std.fs.Dir, | 61 | cache_f: std.fs.Dir, |
| 65 | /// Shared copy of all pcs that have been hit stored in a memory-mapped file that can viewed | 62 | /// Shared copy of all pcs that have been hit stored in a memory-mapped file that can viewed |
| ... | @@ -72,80 +69,12 @@ const Executable = struct { | ... | @@ -72,80 +69,12 @@ const Executable = struct { |
| 72 | /// Used before this structure is initialized to avoid illegal behavior | 69 | /// Used before this structure is initialized to avoid illegal behavior |
| 73 | /// from instrumentation functions being called and using undefined values. | 70 | /// from instrumentation functions being called and using undefined values. |
| 74 | pub const preinit: Executable = .{ | 71 | pub const preinit: Executable = .{ |
| 75 | .rodata_addr = 0, | | |
| 76 | .rodata_size = 0, | | |
| 77 | .pc_counters = undefined, // instrumentation works off the __sancov_cntrs section | 72 | .pc_counters = undefined, // instrumentation works off the __sancov_cntrs section |
| 78 | .cache_f = undefined, | 73 | .cache_f = undefined, |
| 79 | .shared_seen_pcs = undefined, | 74 | .shared_seen_pcs = undefined, |
| 80 | .pc_digest = undefined, | 75 | .pc_digest = undefined, |
| 81 | }; | 76 | }; |
| 82 | | 77 | |
| 83 | /// Even on error, this initializes rodata_addr and rodata_size to valid values | | |
| 84 | fn initRodata(self: *Executable) !void { | | |
| 85 | errdefer { | | |
| 86 | self.rodata_addr = 0; | | |
| 87 | self.rodata_size = 0; | | |
| 88 | } | | |
| 89 | | | |
| 90 | const exec_path = std.fs.selfExePathAlloc(gpa) catch |e| | | |
| 91 | if (e == error.OutOfMemory) @panic("OOM") else return e; | | |
| 92 | defer gpa.free(exec_path); | | |
| 93 | const exec_file = try std.fs.cwd().openFile(exec_path, .{}); | | |
| 94 | defer exec_file.close(); | | |
| 95 | | | |
| 96 | switch (builtin.object_format) { | | |
| 97 | .elf => { | | |
| 98 | // We use two reader instances since the data they respectively read are | | |
| 99 | // not next to each other in the file. | | |
| 100 | // | | |
| 101 | // Multiple instances is safe since Elf.SectionHeaderIterator always calls | | |
| 102 | // seekTo (which we also use to arbitrarily set the index) and we always | | |
| 103 | // call seekTo to arbitrarily read from the string table. | | |
| 104 | var r_buf: [4096]u8 = undefined; | | |
| 105 | var r = exec_file.reader(&r_buf); | | |
| 106 | var str_r_buf: [4096]u8 = undefined; | | |
| 107 | var str_r = exec_file.reader(&str_r_buf); | | |
| 108 | | | |
| 109 | const ehdr: std.elf.Header = try .read(&r.interface); | | |
| 110 | if (ehdr.shstrndx == 0) return error.NoElfStringTable; | | |
| 111 | var shdr_it = ehdr.iterateSectionHeaders(&r); | | |
| 112 | | | |
| 113 | shdr_it.index = ehdr.shstrndx; | | |
| 114 | const str_tab_shdr = try shdr_it.next() orelse return error.InvalidElfSection; | | |
| 115 | const str_tab_off = str_tab_shdr.sh_offset; | | |
| 116 | | | |
| 117 | shdr_it.index = 0; | | |
| 118 | while (try shdr_it.next()) |shdr| { | | |
| 119 | const flags: packed struct { | | |
| 120 | write: bool, | | |
| 121 | alloc: bool, | | |
| 122 | execinstr: bool, | | |
| 123 | } = @bitCast(@as(u3, @truncate(shdr.sh_flags))); | | |
| 124 | if (shdr.sh_addr == 0 or shdr.sh_size == 0 or flags != @TypeOf(flags){ | | |
| 125 | .alloc = true, | | |
| 126 | .write = false, | | |
| 127 | .execinstr = false, | | |
| 128 | }) continue; | | |
| 129 | | | |
| 130 | const rodata_name = ".rodata\x00"; | | |
| 131 | try str_r.seekTo(try math.add(u64, str_tab_off, shdr.sh_name)); | | |
| 132 | const section_name = str_r.interface.take(rodata_name.len) catch return r.err.?; | | |
| 133 | if (!std.mem.eql(u8, section_name, rodata_name)) | | |
| 134 | continue; | | |
| 135 | | | |
| 136 | const addr = math.cast(usize, shdr.sh_addr) orelse return error.Overflow; | | |
| 137 | const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | | |
| 138 | _ = try math.add(usize, addr, size); // make sure there is no overflow | | |
| 139 | self.rodata_addr = addr; | | |
| 140 | self.rodata_size = size; | | |
| 141 | return; | | |
| 142 | } | | |
| 143 | return error.NoRodataSection; | | |
| 144 | }, | | |
| 145 | else => return error.UnsupportedObjectFormat, | | |
| 146 | } | | |
| 147 | } | | |
| 148 | | | |
| 149 | fn getCoverageFile(cache_dir: std.fs.Dir, pcs: []const usize, pc_digest: u64) MemoryMappedList { | 78 | fn getCoverageFile(cache_dir: std.fs.Dir, pcs: []const usize, pc_digest: u64) MemoryMappedList { |
| 150 | const pc_bitset_usizes = bitsetUsizes(pcs.len); | 79 | const pc_bitset_usizes = bitsetUsizes(pcs.len); |
| 151 | const coverage_file_name = std.fmt.hex(pc_digest); | 80 | const coverage_file_name = std.fmt.hex(pc_digest); |
| ... | @@ -284,11 +213,6 @@ const Executable = struct { | ... | @@ -284,11 +213,6 @@ const Executable = struct { |
| 284 | .{ self.pc_counters.len, pcs.len }, | 213 | .{ self.pc_counters.len, pcs.len }, |
| 285 | ); | 214 | ); |
| 286 | | 215 | |
| 287 | self.initRodata() catch |e| if (e != error.UnsupportedObjectFormat) std.log.err( | | |
| 288 | \\failed to enumerate read-only memory: {t} | | |
| 289 | \\efficiency will be severly reduced | | |
| 290 | , .{e}); | | |
| 291 | | | |
| 292 | self.pc_digest = std.hash.Wyhash.hash(0, mem.sliceAsBytes(pcs)); | 216 | self.pc_digest = std.hash.Wyhash.hash(0, mem.sliceAsBytes(pcs)); |
| 293 | self.shared_seen_pcs = getCoverageFile(cache_dir, pcs, self.pc_digest); | 217 | self.shared_seen_pcs = getCoverageFile(cache_dir, pcs, self.pc_digest); |
| 294 | | 218 | |
| ... | @@ -322,33 +246,22 @@ const Executable = struct { | ... | @@ -322,33 +246,22 @@ const Executable = struct { |
| 322 | }; | 246 | }; |
| 323 | }; | 247 | }; |
| 324 | | 248 | |
| 325 | /// Data gathered from instrumentation functions | 249 | /// Data gathered from instrumentation functions. |
| 326 | /// Seperate from Executable since its state is resetable and changes | 250 | /// Seperate from Executable since its state is resetable and changes. |
| 327 | /// Seperate from Fuzzer since it may be needed before fuzzing starts | 251 | /// Seperate from Fuzzer since it may be needed before fuzzing starts. |
| 328 | const Instrumentation = struct { | 252 | const Instrumentation = struct { |
| 329 | /// Bitset of seen pcs across all runs excluding fresh pcs. | 253 | /// Bitset of seen pcs across all runs excluding fresh pcs. |
| 330 | /// This is seperate then shared_seen_pcs because multiple fuzzing processes are likely using | 254 | /// This is seperate then shared_seen_pcs because multiple fuzzing processes are likely using |
| 331 | /// it which causes contention and unrelated pcs to our campaign being set. | 255 | /// it which causes contention and unrelated pcs to our campaign being set. |
| 332 | seen_pcs: []usize, | 256 | seen_pcs: []usize, |
| 333 | /// Bitset of seen rodata bytes read across all runs | | |
| 334 | seen_rodata_loads: []usize, | | |
| 335 | | | |
| 336 | /// Bitset of run's read bytes that weren't present in seen_loads | | |
| 337 | /// Elements are always zero if !any_new_data_loads | | |
| 338 | new_rodata_loads: []usize, | | |
| 339 | any_new_rodata_loads: bool, | | |
| 340 | | 257 | |
| 341 | /// Stores a fresh input's new pcs | 258 | /// Stores a fresh input's new pcs |
| 342 | fresh_pcs: []usize, | 259 | fresh_pcs: []usize, |
| 343 | /// Stores a fresh input's new reads | | |
| 344 | /// Elements are always zero if !any_fresh_rodata_loads | | |
| 345 | fresh_rodata_loads: []usize, | | |
| 346 | any_fresh_rodata_loads: bool, | | |
| 347 | | 260 | |
| 348 | /// Pcs which __sanitizer_cov_trace_switch and __sanitizer_cov_trace_const_cmpx | 261 | /// Pcs which __sanitizer_cov_trace_switch and __sanitizer_cov_trace_const_cmpx |
| 349 | /// have been called from and have had their already been added to const_x_vals | 262 | /// have been called from and have had their already been added to const_x_vals |
| 350 | const_pcs: std.AutoArrayHashMapUnmanaged(usize, void) = .empty, | 263 | const_pcs: std.AutoArrayHashMapUnmanaged(usize, void) = .empty, |
| 351 | /// Values that have been constant operands in comparisons, switch cases, or memory reads | 264 | /// Values that have been constant operands in comparisons and switch cases. |
| 352 | /// There may be duplicates in this array if they came from different addresses, which is | 265 | /// There may be duplicates in this array if they came from different addresses, which is |
| 353 | /// fine as they are likely more important and hence more likely to be selected. | 266 | /// fine as they are likely more important and hence more likely to be selected. |
| 354 | const_vals2: std.ArrayListUnmanaged(u16) = .empty, | 267 | const_vals2: std.ArrayListUnmanaged(u16) = .empty, |
| ... | @@ -361,12 +274,7 @@ const Instrumentation = struct { | ... | @@ -361,12 +274,7 @@ const Instrumentation = struct { |
| 361 | /// from instrumentation functions being called and using undefined values. | 274 | /// from instrumentation functions being called and using undefined values. |
| 362 | pub const preinit: Instrumentation = .{ | 275 | pub const preinit: Instrumentation = .{ |
| 363 | .seen_pcs = undefined, // currently only updated by `Fuzzer` | 276 | .seen_pcs = undefined, // currently only updated by `Fuzzer` |
| 364 | .seen_rodata_loads = undefined, | | |
| 365 | .new_rodata_loads = undefined, | | |
| 366 | .any_new_rodata_loads = undefined, | | |
| 367 | .fresh_pcs = undefined, | 277 | .fresh_pcs = undefined, |
| 368 | .fresh_rodata_loads = undefined, | | |
| 369 | .any_fresh_rodata_loads = undefined, | | |
| 370 | }; | 278 | }; |
| 371 | | 279 | |
| 372 | pub fn depreinit(self: *Instrumentation) void { | 280 | pub fn depreinit(self: *Instrumentation) void { |
| ... | @@ -379,20 +287,14 @@ const Instrumentation = struct { | ... | @@ -379,20 +287,14 @@ const Instrumentation = struct { |
| 379 | | 287 | |
| 380 | pub fn init() Instrumentation { | 288 | pub fn init() Instrumentation { |
| 381 | const pc_bitset_usizes = bitsetUsizes(exec.pc_counters.len); | 289 | const pc_bitset_usizes = bitsetUsizes(exec.pc_counters.len); |
| 382 | const rodata_bitset_usizes = bitsetUsizes(exec.rodata_size); | 290 | const alloc_usizes = pc_bitset_usizes * 2; |
| 383 | const alloc_usizes = pc_bitset_usizes * 2 + rodata_bitset_usizes * 3; | | |
| 384 | const buf = gpa.alloc(u8, alloc_usizes * @sizeOf(usize)) catch @panic("OOM"); | 291 | const buf = gpa.alloc(u8, alloc_usizes * @sizeOf(usize)) catch @panic("OOM"); |
| 385 | var fba_ctx: std.heap.FixedBufferAllocator = .init(buf); | 292 | var fba_ctx: std.heap.FixedBufferAllocator = .init(buf); |
| 386 | const fba = fba_ctx.allocator(); | 293 | const fba = fba_ctx.allocator(); |
| 387 | | 294 | |
| 388 | var self: Instrumentation = .{ | 295 | var self: Instrumentation = .{ |
| 389 | .seen_pcs = fba.alloc(usize, pc_bitset_usizes) catch unreachable, | 296 | .seen_pcs = fba.alloc(usize, pc_bitset_usizes) catch unreachable, |
| 390 | .seen_rodata_loads = fba.alloc(usize, rodata_bitset_usizes) catch unreachable, | | |
| 391 | .new_rodata_loads = fba.alloc(usize, rodata_bitset_usizes) catch unreachable, | | |
| 392 | .any_new_rodata_loads = undefined, | | |
| 393 | .fresh_pcs = fba.alloc(usize, pc_bitset_usizes) catch unreachable, | 297 | .fresh_pcs = fba.alloc(usize, pc_bitset_usizes) catch unreachable, |
| 394 | .fresh_rodata_loads = fba.alloc(usize, rodata_bitset_usizes) catch unreachable, | | |
| 395 | .any_fresh_rodata_loads = undefined, | | |
| 396 | }; | 298 | }; |
| 397 | self.reset(); | 299 | self.reset(); |
| 398 | return self; | 300 | return self; |
| ... | @@ -400,12 +302,7 @@ const Instrumentation = struct { | ... | @@ -400,12 +302,7 @@ const Instrumentation = struct { |
| 400 | | 302 | |
| 401 | pub fn reset(self: *Instrumentation) void { | 303 | pub fn reset(self: *Instrumentation) void { |
| 402 | @memset(self.seen_pcs, 0); | 304 | @memset(self.seen_pcs, 0); |
| 403 | @memset(self.seen_rodata_loads, 0); | | |
| 404 | @memset(self.new_rodata_loads, 0); | | |
| 405 | self.any_new_rodata_loads = false; | | |
| 406 | @memset(self.fresh_pcs, 0); | 305 | @memset(self.fresh_pcs, 0); |
| 407 | @memset(self.fresh_rodata_loads, 0); | | |
| 408 | self.any_fresh_rodata_loads = false; | | |
| 409 | self.const_pcs.clearRetainingCapacity(); | 306 | self.const_pcs.clearRetainingCapacity(); |
| 410 | self.const_vals2.clearRetainingCapacity(); | 307 | self.const_vals2.clearRetainingCapacity(); |
| 411 | self.const_vals4.clearRetainingCapacity(); | 308 | self.const_vals4.clearRetainingCapacity(); |
| ... | @@ -418,16 +315,7 @@ const Instrumentation = struct { | ... | @@ -418,16 +315,7 @@ const Instrumentation = struct { |
| 418 | return (self.const_pcs.getOrPut(gpa, pc) catch @panic("OOM")).found_existing; | 315 | return (self.const_pcs.getOrPut(gpa, pc) catch @panic("OOM")).found_existing; |
| 419 | } | 316 | } |
| 420 | | 317 | |
| 421 | pub fn clearNewRodataLoads(self: *Instrumentation) void { | | |
| 422 | if (self.any_new_rodata_loads) { | | |
| 423 | @memset(self.new_rodata_loads, 0); | | |
| 424 | self.any_new_rodata_loads = false; | | |
| 425 | } | | |
| 426 | } | | |
| 427 | | | |
| 428 | pub fn isFresh(self: *Instrumentation) bool { | 318 | pub fn isFresh(self: *Instrumentation) bool { |
| 429 | if (self.any_new_rodata_loads) return true; | | |
| 430 | | | |
| 431 | var hit_pcs = exec.pcBitsetIterator(); | 319 | var hit_pcs = exec.pcBitsetIterator(); |
| 432 | for (self.seen_pcs) |seen_pcs| { | 320 | for (self.seen_pcs) |seen_pcs| { |
| 433 | if (hit_pcs.next() & ~seen_pcs != 0) return true; | 321 | if (hit_pcs.next() & ~seen_pcs != 0) return true; |
| ... | @@ -436,38 +324,24 @@ const Instrumentation = struct { | ... | @@ -436,38 +324,24 @@ const Instrumentation = struct { |
| 436 | return false; | 324 | return false; |
| 437 | } | 325 | } |
| 438 | | 326 | |
| 439 | /// Updates fresh_pcs and fresh_rodata_loads | 327 | /// Updates `fresh_pcs` |
| 440 | /// any_new_rodata_loads and elements of new_rodata_loads are unspecified | | |
| 441 | /// afterwards, but still valid. | | |
| 442 | pub fn setFresh(self: *Instrumentation) void { | 328 | pub fn setFresh(self: *Instrumentation) void { |
| 443 | var hit_pcs = exec.pcBitsetIterator(); | 329 | var hit_pcs = exec.pcBitsetIterator(); |
| 444 | for (self.seen_pcs, self.fresh_pcs) |seen_pcs, *fresh_pcs| { | 330 | for (self.seen_pcs, self.fresh_pcs) |seen_pcs, *fresh_pcs| { |
| 445 | fresh_pcs.* = hit_pcs.next() & ~seen_pcs; | 331 | fresh_pcs.* = hit_pcs.next() & ~seen_pcs; |
| 446 | } | 332 | } |
| 447 | | | |
| 448 | mem.swap([]usize, &self.fresh_rodata_loads, &self.new_rodata_loads); | | |
| 449 | mem.swap(bool, &self.any_fresh_rodata_loads, &self.any_new_rodata_loads); | | |
| 450 | } | 333 | } |
| 451 | | 334 | |
| 452 | /// Returns if exec.pc_counters and new_rodata_loads are the same or a superset of fresh_pcs and | 335 | /// Returns if `exec.pc_counters` is a superset of `fresh_pcs`. |
| 453 | /// fresh_rodata_loads respectively. | | |
| 454 | pub fn atleastFresh(self: *Instrumentation) bool { | 336 | pub fn atleastFresh(self: *Instrumentation) bool { |
| 455 | var hit_pcs = exec.pcBitsetIterator(); | 337 | var hit_pcs = exec.pcBitsetIterator(); |
| 456 | for (self.fresh_pcs) |fresh_pcs| { | 338 | for (self.fresh_pcs) |fresh_pcs| { |
| 457 | if (fresh_pcs & hit_pcs.next() != fresh_pcs) return false; | 339 | if (fresh_pcs & hit_pcs.next() != fresh_pcs) return false; |
| 458 | } | 340 | } |
| 459 | | | |
| 460 | if (self.any_fresh_rodata_loads) { | | |
| 461 | if (!self.any_new_rodata_loads) return false; | | |
| 462 | for (self.new_rodata_loads, self.fresh_rodata_loads) |n, f| { | | |
| 463 | if (n & f != f) return false; | | |
| 464 | } | | |
| 465 | } | | |
| 466 | | | |
| 467 | return true; | 341 | return true; |
| 468 | } | 342 | } |
| 469 | | 343 | |
| 470 | /// Updates based off fresh_pcs and fresh_rodata_loads | 344 | /// Updates based off `fresh_pcs` |
| 471 | fn updateSeen(self: *Instrumentation) void { | 345 | fn updateSeen(self: *Instrumentation) void { |
| 472 | comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_bits_usize); | 346 | comptime assert(abi.SeenPcsHeader.trailing[0] == .pc_bits_usize); |
| 473 | const shared_seen_pcs: [*]volatile usize = @ptrCast( | 347 | const shared_seen_pcs: [*]volatile usize = @ptrCast( |
| ... | @@ -479,11 +353,6 @@ const Instrumentation = struct { | ... | @@ -479,11 +353,6 @@ const Instrumentation = struct { |
| 479 | if (fresh != 0) | 353 | if (fresh != 0) |
| 480 | _ = @atomicRmw(usize, shared_seen, .Or, fresh, .monotonic); | 354 | _ = @atomicRmw(usize, shared_seen, .Or, fresh, .monotonic); |
| 481 | } | 355 | } |
| 482 | | | |
| 483 | if (self.any_fresh_rodata_loads) { | | |
| 484 | for (self.seen_rodata_loads, self.fresh_rodata_loads) |*s, f| | | |
| 485 | s.* |= f; | | |
| 486 | } | | |
| 487 | } | 356 | } |
| 488 | }; | 357 | }; |
| 489 | | 358 | |
| ... | @@ -496,8 +365,8 @@ const Fuzzer = struct { | ... | @@ -496,8 +365,8 @@ const Fuzzer = struct { |
| 496 | /// input. | 365 | /// input. |
| 497 | input: MemoryMappedList, | 366 | input: MemoryMappedList, |
| 498 | | 367 | |
| 499 | /// Minimized past inputs leading to new pcs or rodata reads. These are randomly mutated in | 368 | /// Minimized past inputs leading to new pc hits. |
| 500 | /// round-robin fashion | 369 | /// These are randomly mutated in round-robin fashion |
| 501 | /// Element zero is always an empty input. It is gauraunteed no other elements are empty. | 370 | /// Element zero is always an empty input. It is gauraunteed no other elements are empty. |
| 502 | corpus: std.ArrayListUnmanaged([]const u8), | 371 | corpus: std.ArrayListUnmanaged([]const u8), |
| 503 | corpus_pos: usize, | 372 | corpus_pos: usize, |
| ... | @@ -596,10 +465,9 @@ const Fuzzer = struct { | ... | @@ -596,10 +465,9 @@ const Fuzzer = struct { |
| 596 | self.run(); | 465 | self.run(); |
| 597 | inst.setFresh(); | 466 | inst.setFresh(); |
| 598 | inst.updateSeen(); | 467 | inst.updateSeen(); |
| 599 | inst.clearNewRodataLoads(); | | |
| 600 | } | 468 | } |
| 601 | | 469 | |
| 602 | /// Assumes fresh_pcs and fresh_rodata_loads correspond to the input | 470 | /// Assumes `fresh_pcs` correspond to the input |
| 603 | fn minimizeInput(self: *Fuzzer) void { | 471 | fn minimizeInput(self: *Fuzzer) void { |
| 604 | // The minimization technique is kept relatively simple, we sequentially try to remove each | 472 | // The minimization technique is kept relatively simple, we sequentially try to remove each |
| 605 | // byte and check that the new pcs and memory loads are still hit. | 473 | // byte and check that the new pcs and memory loads are still hit. |
| ... | @@ -609,7 +477,6 @@ const Fuzzer = struct { | ... | @@ -609,7 +477,6 @@ const Fuzzer = struct { |
| 609 | const old = self.input.orderedRemove(i); | 477 | const old = self.input.orderedRemove(i); |
| 610 | | 478 | |
| 611 | @memset(exec.pc_counters, 0); | 479 | @memset(exec.pc_counters, 0); |
| 612 | inst.clearNewRodataLoads(); | | |
| 613 | self.run(); | 480 | self.run(); |
| 614 | | 481 | |
| 615 | if (!inst.atleastFresh()) { | 482 | if (!inst.atleastFresh()) { |
| ... | @@ -623,11 +490,7 @@ const Fuzzer = struct { | ... | @@ -623,11 +490,7 @@ const Fuzzer = struct { |
| 623 | } | 490 | } |
| 624 | | 491 | |
| 625 | fn run(self: *Fuzzer) void { | 492 | fn run(self: *Fuzzer) void { |
| 626 | // We don't need to clear pc_counters here; all we care about is new hits and not already | 493 | // `pc_counters` is not cleared since only new hits are relevant. |
| 627 | // seen hits. Ideally, we wouldn't even have these counters and do something similiar to | | |
| 628 | // what we do for tracking memory (i.e. a __sanitizer_cov function that updates a flag on a | | |
| 629 | // new hit.) | | |
| 630 | assert(!inst.any_new_rodata_loads); | | |
| 631 | | 494 | |
| 632 | mem.bytesAsValue(usize, self.input.items[0..8]).* = | 495 | mem.bytesAsValue(usize, self.input.items[0..8]).* = |
| 633 | mem.nativeToLittle(usize, self.input.items.len - 8); | 496 | mem.nativeToLittle(usize, self.input.items.len - 8); |
| ... | @@ -673,7 +536,6 @@ const Fuzzer = struct { | ... | @@ -673,7 +536,6 @@ const Fuzzer = struct { |
| 673 | inst.setFresh(); | 536 | inst.setFresh(); |
| 674 | self.minimizeInput(); | 537 | self.minimizeInput(); |
| 675 | inst.updateSeen(); | 538 | inst.updateSeen(); |
| 676 | inst.clearNewRodataLoads(); | | |
| 677 | | 539 | |
| 678 | // An empty-input has always been tried, so if an empty input is fresh then the | 540 | // An empty-input has always been tried, so if an empty input is fresh then the |
| 679 | // test has to be non-deterministic. This has to be checked as duplicate empty | 541 | // test has to be non-deterministic. This has to be checked as duplicate empty |
| ... | @@ -796,58 +658,6 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases: [*]const u64) void { | ... | @@ -796,58 +658,6 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases: [*]const u64) void { |
| 796 | } | 658 | } |
| 797 | } | 659 | } |
| 798 | | 660 | |
| 799 | fn genericLoad(T: anytype, ptr: *align(1) const T, comptime opt_const_vals_field: ?[]const u8) void { | | |
| 800 | const addr = @intFromPtr(ptr); | | |
| 801 | const off = addr -% exec.rodata_addr; | | |
| 802 | if (off >= exec.rodata_size) { | | |
| 803 | @branchHint(.likely); | | |
| 804 | return; | | |
| 805 | } | | |
| 806 | | | |
| 807 | const i = off / @bitSizeOf(usize); | | |
| 808 | // Bits are intentionally truncated since the pointer will almost always be aligned | | |
| 809 | const hit = (@as(usize, (1 << @sizeOf(T)) - 1)) << @intCast(off % @bitSizeOf(usize)); | | |
| 810 | const new = hit & ~inst.seen_rodata_loads[i]; | | |
| 811 | if (new == 0) { | | |
| 812 | @branchHint(.likely); | | |
| 813 | return; | | |
| 814 | } | | |
| 815 | | | |
| 816 | inst.new_rodata_loads[i] |= new; | | |
| 817 | inst.any_new_rodata_loads = true; | | |
| 818 | | | |
| 819 | if (opt_const_vals_field) |const_vals_field| { | | |
| 820 | // This may have already been hit and this run is just being used for evaluating the | | |
| 821 | // input, in which case we do not want to readd the same value. | | |
| 822 | if (inst.any_fresh_rodata_loads) { | | |
| 823 | @branchHint(.unlikely); | | |
| 824 | if (new & ~inst.fresh_rodata_loads[i] == 0) | | |
| 825 | return; | | |
| 826 | } | | |
| 827 | @field(inst, const_vals_field).append(gpa, ptr.*) catch @panic("OOM"); | | |
| 828 | } | | |
| 829 | } | | |
| 830 | | | |
| 831 | export fn __sanitizer_cov_load1(ptr: *align(1) const u8) void { | | |
| 832 | genericLoad(u8, ptr, null); | | |
| 833 | } | | |
| 834 | | | |
| 835 | export fn __sanitizer_cov_load2(ptr: *align(1) const u16) void { | | |
| 836 | genericLoad(u16, ptr, "const_vals2"); | | |
| 837 | } | | |
| 838 | | | |
| 839 | export fn __sanitizer_cov_load4(ptr: *align(1) const u32) void { | | |
| 840 | genericLoad(u32, ptr, "const_vals4"); | | |
| 841 | } | | |
| 842 | | | |
| 843 | export fn __sanitizer_cov_load8(ptr: *align(1) const u64) void { | | |
| 844 | genericLoad(u64, ptr, "const_vals8"); | | |
| 845 | } | | |
| 846 | | | |
| 847 | export fn __sanitizer_cov_load16(ptr: *align(1) const u128) void { | | |
| 848 | genericLoad(u128, ptr, "const_vals16"); | | |
| 849 | } | | |
| 850 | | | |
| 851 | export fn __sanitizer_cov_trace_cmp1(arg1: u8, arg2: u8) void { | 661 | export fn __sanitizer_cov_trace_cmp1(arg1: u8, arg2: u8) void { |
| 852 | _ = arg1; | 662 | _ = arg1; |
| 853 | _ = arg2; | 663 | _ = arg2; |