╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ fuzzer.zig ───────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
2286 // The LLVM backend seems to insert placeholder values of `1` in __sancov_pcs1 2287 if (addr == 1) return 1; 2288 panic("failed to find virtual address slide for address 0x{x}: {t}", .{ addr, err }); 2289 }; 2290 return addr - slide; 2291 } 2292 2293 /// Helps determine run uniqueness in the face of recursion. 2294 /// Currently not used by the fuzzer. 2295 export threadlocal var __sancov_lowest_stack: usize = 0; 2296 2297 export fn __sanitizer_cov_trace_pc_indir(callee: usize) void { 2298 // Not valuable because we already have pc tracing via 8bit counters. 2299 _ = callee; 2300 } 2301 export fn __sanitizer_cov_8bit_counters_init(start: usize, end: usize) void { 2302 // clang will emit a call to this function when compiling with code coverage instrumentation. 2303 // however, fuzzer_init() does not need this information since it directly reads from the 2304 // symbol table. 2305 _ = start; 2306 _ = end; 2307 } 2308 export fn __sanitizer_cov_pcs_init(start: usize, end: usize) void { 2309 // clang will emit a call to this function when compiling with code coverage instrumentation. 2310 // however, fuzzer_init() does not need this information since it directly reads from the 2311 // symbol table. 2312 _ = start; 2313 _ = end; 2314 } 2315 2316 /// Reusable and recoverable input. 2317 /// 2318 /// Has a 32-bit limit on the input length. This has the nice side effect that `u32` 2319 /// can be used in most placed in `fuzzer` with the last `@sizeOf(abi.MmapInputHeader)` 2320 /// values reserved. 2321 const MemoryMappedInput = struct { 2322 const Header = abi.MmapInputHeader; 2323 2324 len: u32, 2325 /// Directly accessing `memory` is unsafe, use either `inputSlice` or `writeSlice`. 2326 mmap: Io.File.MemoryMap, 2327 in_i: u32, 2328 2329 /// `file` becomes owned by the returned `MemoryMappedInput` 2330 pub fn init(file: Io.File, instance_id: u32, in_i: u32) MemoryMappedInput { 2331 var size = file.length(io) catch |e| 2332 panic("failed to get length of 'in{x}': {t}", .{ in_i, e }); 2333 if (size < std.heap.page_size_max) { 2334 size = std.heap.page_size_max; 2335 file.setLength(io, size) catch |e| 2336 panic("failed to resize 'in{x}': {t}", .{ in_i, e }); 2337 } 2338 const map = file.createMemoryMap(io, .{ .len = size }) catch |e| 2339 panic("failed to memmap input file 'in{x}': {t}", .{ in_i, e }); 2340 @as(*volatile Header, @ptrCast(map.memory)).* = .{ 2341 .pc_digest = mem.nativeToLittle(u64, exec.pc_digest), 2342 .instance_id = mem.nativeToLittle(u32, instance_id), 2343 .test_i = 0, 2344 .len = 0, 2345 }; 2346 return .{ 2347 .len = 0, 2348 .mmap = map, 2349 .in_i = in_i, 2350 }; 2351 } 2352 2353 pub fn deinit(l: *MemoryMappedInput) void { 2354 const f = l.mmap.file; 2355 l.mmap.write(io) catch |e| panic("failed to write memory map of 'in{x}': {t}", .{ l.in_i, e }); 2356 l.mmap.destroy(io); 2357 f.close(io); 2358 l.* = undefined; 2359 } 2360 2361 /// Modify the array so that it can hold at least `additional_count` **more** items. 2362 /// 2363 /// Invalidates element pointers if additional memory is needed. 2364 pub fn ensureUnusedCapacity(l: *MemoryMappedInput, additional_count: usize) void { 2365 return l.ensureSize(@sizeOf(Header) + l.len + additional_count); 2366 } 2367 2368 fn ensureSize(l: *MemoryMappedInput, min_capacity: usize) void { 2369 if (l.mmap.memory.len < min_capacity) { 2370 @branchHint(.unlikely); 2371 2372 const max_capacity = 1 << 32; // The size of the header is not added 2373 // in order to keep the capacity page aligned and to allow those values to 2374 // reserved for other places. 2375 if (min_capacity > max_capacity) @panic("too much smith data requested"); 2376 2377 const new_capacity = @min(growCapacity(min_capacity), max_capacity); 2378 l.mmap.file.setLength(io, new_capacity) catch |e| 2379 panic("failed to resize 'in{x}': {t}", .{ l.in_i, e }); 2380 l.mmap.setLength(io, new_capacity) catch |se| switch (se) { 2381 error.OperationUnsupported => { 2382 const f = l.mmap.file; 2383 l.mmap.destroy(io); 2384 l.mmap = f.createMemoryMap(io, .{ .len = new_capacity }) catch |e| 2385 panic("failed to memory map 'in{x}': {t}", .{ l.in_i, e }); 2386 }, 2387 else => panic("failed to resize memory map of 'in{x}': {t}", .{ l.in_i, se }), 2388 }; 2389 } 2390 } 2391 2392 // Only writing has side effects, so volatile is not needed 2393 pub fn inputSlice(l: *MemoryMappedInput) []const u8 { 2394 return l.mmap.memory[@sizeOf(Header)..][0..l.len]; 2395 } 2396 2397 // Writing has side effectsd, so volatile is necessary 2398 pub fn writeSlice(l: *MemoryMappedInput) []volatile u8 { 2399 return l.mmap.memory; 2400 } 2401 2402 fn writeLen(l: *MemoryMappedInput) void { 2403 l.writeSlice()[@offsetOf(Header, "len")..][0..4].* = 2404 @bitCast(mem.nativeToLittle(u32, l.len)); 2405 } 2406 2407 pub fn setTest(l: *MemoryMappedInput, i: u32) void { 2408 l.writeSlice()[@offsetOf(Header, "test_i")..][0..4].* = 2409 @bitCast(mem.nativeToLittle(u32, i)); 2410 } 2411 2412 /// Invalidates all element pointers. 2413 pub fn clearRetainingCapacity(l: *MemoryMappedInput) void { 2414 l.len = 0; 2415 l.writeLen(); 2416 } 2417 2418 /// Append the slice of items to the list. 2419 /// 2420 /// Invalidates item pointers if more space is required. 2421 pub fn appendSlice(l: *MemoryMappedInput, items: []const u8) void { 2422 l.ensureUnusedCapacity(items.len); 2423 @memcpy(l.writeSlice()[@sizeOf(Header) + l.len ..][0..items.len], items); 2424 l.len += @as(u32, @intCast(items.len)); 2425 l.writeLen(); 2426 } 2427 2428 /// Append the little-endian integer to the list. 2429 /// 2430 /// Invalidates item pointers if more space is required. 2431 pub fn appendLittleInt(l: *MemoryMappedInput, T: type, x: T) void { 2432 l.ensureUnusedCapacity(@sizeOf(T)); 2433 l.writeSlice()[@sizeOf(Header) + l.len ..][0..@sizeOf(T)].* = 2434 @bitCast(mem.nativeToLittle(T, x)); 2435 l.len += @sizeOf(T); 2436 l.writeLen(); 2437 } 2438 2439 /// Called when memory growth is necessary. Returns a capacity larger than 2440 /// minimum that grows super-linearly. 2441 fn growCapacity(minimum: usize) usize { 2442 return mem.alignForward( 2443 usize, 2444 minimum +| (minimum / 2 + std.heap.page_size_max), 2445 std.heap.page_size_max, 2446 ); 2447 } 2448 }; 2449