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
// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Craton Software Company
//! Property-based round-trip test for the kernel-argv wire format.
//!
//! Goal: any `Vec<LoweredArg>` produced through the supported public
//! constructors must survive an `encode_argv` -> `parse_argv` round-trip
//! losslessly, modulo the one documented normalisation — the resolved
//! `host_ptr` inside a [`LoweredArg::Ptr`] is not part of the wire format
//! and is reconstructed by `parse_argv` from the guest's linear memory.
//!
//! Compared to the hand-rolled cases in `kernel_args.rs::tests`, the
//! proptest sweeps many more permutations of mixed argv layouts — covering
//! corners like trailing pointer args, all-pointer argv, deeply-negative
//! `i64`/`f64` bit patterns, and signalling NaNs — that would be tedious
//! to enumerate by hand. The hand-rolled tests stay because they pin the
//! exact byte-for-byte wire format; the proptest pins the *roundtrip*
//! contract.
//!
//! NaN handling: `LoweredArg`'s `PartialEq` is derived, so `f32`/`f64`
//! NaN fails the naive `assert_eq!(parsed, original)`. We compare value
//! bit-patterns (`to_bits`) for the float variants instead, which is the
//! property the wire format actually preserves.
use *;
use ;
/// Backing slice big enough for any pointer arg generated by
/// `arb_lowered_arg` (offset + len each capped at 1024, so the widest
/// window is `[0, 2048)`). 4 KiB matches the `fake_mem()` helper used
/// in `kernel_args.rs::tests` and the `fuzz_parse_argv` target.
const FAKE_MEM_BYTES: usize = 4096;
/// Strategy producing one arbitrary [`LoweredArg`] via the supported
/// public constructors.
///
/// Scalar variants are stamped directly; the [`LoweredArg::Ptr`] variant
/// is built through [`LoweredArg::ptr_for_encoding`] because the variant
/// is `#[non_exhaustive]` (struct-literal construction from outside the
/// crate is blocked by design — see the kernel_args.rs docs). The ptr
/// offset+len bounds (`0..1024`) keep the resolved window inside
/// [`FAKE_MEM_BYTES`] so the bounds-check in `parse_argv` never trips,
/// isolating the property under test (lossless roundtrip) from the
/// bounds-check itself, which has its own dedicated unit tests.
/// Compare two [`LoweredArg`] values for the roundtrip property.
///
/// The derived `PartialEq` uses `f32::eq` / `f64::eq` which both return
/// `false` for NaN; the wire format, however, preserves every bit
/// (`from_le_bytes` is a memcpy). We compare bit-patterns for the float
/// variants and fall back to the derived `PartialEq` for the others.
/// `Ptr` arguments compare by `(guest_offset, len)` only — the resolved
/// `host_ptr` is reconstructed from `mem` by `parse_argv` and so cannot
/// match the null placeholder the encoder side carried.
proptest!