@@ -1164,4 +1164,159 @@ mod proofs {
11641164 assert ! ( Step :: forward( start, count) == end) ;
11651165 }
11661166 }
1167+
1168+ mod phys_addr {
1169+ use super :: * ;
1170+
1171+ // The next two proof harnesses prove the correctness of the `forward`
1172+ // implementation of PhysAddr.
1173+
1174+ // This harness proves that our implementation can correctly take 0 or 1
1175+ // step starting from any address.
1176+ #[ kani:: proof]
1177+ fn forward_base_case ( ) {
1178+ let start_raw: u64 = kani:: any ( ) ;
1179+ let Ok ( start) = PhysAddr :: try_new ( start_raw) else {
1180+ return ;
1181+ } ;
1182+
1183+ // Adding 0 to any address should always yield the same address.
1184+ let same = Step :: forward ( start, 0 ) ;
1185+ assert ! ( start == same) ;
1186+
1187+ // Manually calculate the expected address after stepping once.
1188+ let expected = match start_raw {
1189+ // Adding 1 to addresses in this range will result in a valid
1190+ // address.
1191+ 0x0000_0000_0000_0000 ..=0xf_ffff_ffff_fffe => Some ( start_raw + 1 ) ,
1192+ // Adding 1 to this address causes an overflow.
1193+ 0xf_ffff_ffff_ffff => None ,
1194+ // Bigger addresses do not exist.
1195+ _ => unreachable ! ( ) ,
1196+ } ;
1197+ if let Some ( expected) = expected {
1198+ // Verify that `expected` is a valid address.
1199+ assert ! ( PhysAddr :: try_new( expected) . is_ok( ) ) ;
1200+ }
1201+ // Verify `forward_checked`.
1202+ let next = Step :: forward_checked ( start, 1 ) ;
1203+ assert ! ( next. map( PhysAddr :: as_u64) == expected) ;
1204+ }
1205+
1206+ // This harness proves that the result of taking two small steps is the
1207+ // same as taking one combined large step.
1208+ #[ kani:: proof]
1209+ fn forward_induction_step ( ) {
1210+ let start_raw: u64 = kani:: any ( ) ;
1211+ let Ok ( start) = PhysAddr :: try_new ( start_raw) else {
1212+ return ;
1213+ } ;
1214+
1215+ let count1: usize = kani:: any ( ) ;
1216+ let count2: usize = kani:: any ( ) ;
1217+ // If we can take two small steps...
1218+ let Some ( next1) = Step :: forward_checked ( start, count1) else {
1219+ return ;
1220+ } ;
1221+ let Some ( next2) = Step :: forward_checked ( next1, count2) else {
1222+ return ;
1223+ } ;
1224+
1225+ // ...then we can also take one combined large step.
1226+ let count_both = count1 + count2;
1227+ let next_both = Step :: forward ( start, count_both) ;
1228+ assert ! ( next2 == next_both) ;
1229+ }
1230+
1231+ // The next two proof harnesses prove the correctness of the `backward`
1232+ // implementation of PhysAddr using the `forward` implementation which
1233+ // we've already proven to be correct.
1234+ // They do this by proving the symmetry between those two functions.
1235+
1236+ // This harness proves the correctness of the implementation of `backward`
1237+ // for all inputs for which `forward_checked` succeeds.
1238+ #[ kani:: proof]
1239+ fn forward_implies_backward ( ) {
1240+ let start_raw: u64 = kani:: any ( ) ;
1241+ let Ok ( start) = PhysAddr :: try_new ( start_raw) else {
1242+ return ;
1243+ } ;
1244+ let count: usize = kani:: any ( ) ;
1245+
1246+ // If `forward_checked` succeeds...
1247+ let Some ( end) = Step :: forward_checked ( start, count) else {
1248+ return ;
1249+ } ;
1250+
1251+ // ...then `backward` succeeds as well.
1252+ let start2 = Step :: backward ( end, count) ;
1253+ assert ! ( start == start2) ;
1254+ }
1255+
1256+ // This harness proves that for all inputs for which `backward_checked`
1257+ // succeeds, `forward` succeeds as well.
1258+ #[ kani:: proof]
1259+ fn backward_implies_forward ( ) {
1260+ let end_raw: u64 = kani:: any ( ) ;
1261+ let Ok ( end) = PhysAddr :: try_new ( end_raw) else {
1262+ return ;
1263+ } ;
1264+ let count: usize = kani:: any ( ) ;
1265+
1266+ // If `backward_checked` succeeds...
1267+ let Some ( start) = Step :: backward_checked ( end, count) else {
1268+ return ;
1269+ } ;
1270+
1271+ // ...then `forward` succeeds as well.
1272+ let end2 = Step :: forward ( start, count) ;
1273+ assert ! ( end == end2) ;
1274+ }
1275+
1276+ // The next two proof harnesses prove the correctness of the
1277+ // `steps_between` implementation of PhysAddr using the `forward`
1278+ // implementation which we've already proven to be correct.
1279+ // They do this by proving the symmetry between those two functions.
1280+
1281+ // This harness proves the correctness of the implementation of
1282+ // `steps_between` for all inputs for which `forward_checked` succeeds.
1283+ #[ kani:: proof]
1284+ fn forward_implies_steps_between ( ) {
1285+ let start: u64 = kani:: any ( ) ;
1286+ let Ok ( start) = PhysAddr :: try_new ( start) else {
1287+ return ;
1288+ } ;
1289+ let count: usize = kani:: any ( ) ;
1290+
1291+ // If `forward_checked` succeeds...
1292+ let Some ( end) = Step :: forward_checked ( start, count) else {
1293+ return ;
1294+ } ;
1295+
1296+ // ...then `steps_between` succeeds as well.
1297+ assert ! ( Step :: steps_between( & start, & end) == ( count, Some ( count) ) ) ;
1298+ }
1299+
1300+ // This harness proves that for all inputs for which `steps_between`
1301+ // succeeds, `forward` succeeds as well.
1302+ #[ kani:: proof]
1303+ fn steps_between_implies_forward ( ) {
1304+ let start: u64 = kani:: any ( ) ;
1305+ let Ok ( start) = PhysAddr :: try_new ( start) else {
1306+ return ;
1307+ } ;
1308+ let end: u64 = kani:: any ( ) ;
1309+ let Ok ( end) = PhysAddr :: try_new ( end) else {
1310+ return ;
1311+ } ;
1312+
1313+ // If `steps_between` succeeds...
1314+ let Some ( count) = Step :: steps_between ( & start, & end) . 1 else {
1315+ return ;
1316+ } ;
1317+
1318+ // ...then `forward` succeeds as well.
1319+ assert ! ( Step :: forward( start, count) == end) ;
1320+ }
1321+ }
11671322}
0 commit comments