treegen: Require at least one mutation
authorColin Walters <walters@verbum.org>
Fri, 17 Mar 2023 17:17:11 +0000 (13:17 -0400)
committerColin Walters <walters@verbum.org>
Thu, 23 Mar 2023 20:48:55 +0000 (16:48 -0400)
Since a later assertion would otherwise trigger.  We saw
this happen in CI.

tests/inst/src/treegen.rs

index 8d65f02bb4062060d03f2156f89d287e23445beb..771611400794af2cefa9030948b645547ec4c4ff 100644 (file)
@@ -76,36 +76,48 @@ pub(crate) fn mutate_one_executable_to(
 /// Find ELF files in the srcdir, write new copies to dest (only percentage)
 pub(crate) fn mutate_executables_to(src: &Dir, dest: &Dir, percentage: u32) -> Result<u32> {
     assert!(percentage > 0 && percentage <= 100);
+    println!("Mutating {percentage} executables");
     let mut mutated = 0;
-    for entry in src.entries()? {
-        let entry = entry?;
-        if entry.file_type()? != cap_std::fs::FileType::file() {
-            continue;
-        }
-        let meta = entry.metadata()?;
-        let mode = meta.mode();
-        // Must be executable
-        if mode & (libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH) == 0 {
-            continue;
-        }
-        // Not suid
-        if mode & (libc::S_ISUID | libc::S_ISGID) == 0 {
-            continue;
-        }
-        // Greater than 1k in size
-        if meta.size() < 1024 {
-            continue;
-        }
-        let mut f = entry.open()?.into_std();
-        if !is_elf(&mut f)? {
-            continue;
+    // Retry until we change at least one
+    'outer: loop {
+        let mut candidates = 0;
+        for entry in src.entries()? {
+            let entry = entry?;
+            if entry.file_type()? != cap_std::fs::FileType::file() {
+                continue;
+            }
+            let meta = entry.metadata()?;
+            let mode = meta.mode();
+            // Must be executable
+            if mode & (libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH) == 0 {
+                continue;
+            }
+            // Not suid
+            if mode & (libc::S_ISUID | libc::S_ISGID) == 0 {
+                continue;
+            }
+            // Greater than 1k in size
+            if meta.size() < 1024 {
+                continue;
+            }
+            let mut f = entry.open()?.into_std();
+            if !is_elf(&mut f)? {
+                continue;
+            }
+            candidates += 1;
+            if !rand::thread_rng().gen_ratio(percentage, 100) {
+                continue;
+            }
+            mutate_one_executable_to(&mut f, &entry.file_name(), dest)
+                .with_context(|| format!("Failed updating {:?}", entry.file_name()))?;
+            mutated += 1;
+            break 'outer;
         }
-        if !rand::thread_rng().gen_ratio(percentage, 100) {
-            continue;
+        println!("Changed {mutated} binaries of {candidates}");
+        // If there's nothing to change, we're done
+        if candidates == 0 {
+            break;
         }
-        mutate_one_executable_to(&mut f, &entry.file_name(), dest)
-            .with_context(|| format!("Failed updating {:?}", entry.file_name()))?;
-        mutated += 1;
     }
     Ok(mutated)
 }