Spotted while fixing #2327 (PR #2338). Filed separately rather than widened into that diff, since it is a distinct defect with a distinct fix.
What
scripts/tri_loop/damage_repair.py parses argv by hand and has no else branch, so any unrecognised flag is silently ignored and the run continues as if it were not there:
for i, a in enumerate(argv):
if a == "--snapshot" and i + 1 < len(argv):
snapshot = argv[i + 1]
elif a == "--binary" and i + 1 < len(argv):
binary = argv[i + 1]
elif a == "--class" and i + 1 < len(argv):
only = argv[i + 1]
elif a == "--apply-to" and i + 1 < len(argv):
apply_to = argv[i + 1]
elif a == "--json" and i + 1 < len(argv):
json_out = argv[i + 1]
The i + 1 < len(argv) guards have the same shape: a flag given as the last argument, with its value missing, is also ignored rather than rejected.
Why it matters
--class narrows the run to a single damage class. Typo it and the tool repairs every class instead, and exits 0 reporting success — the operator asked for a scoped run and got a corpus-wide one, with no signal that the scope was dropped.
Reproduction
Two-class corpus, damage-repair from origin/master:
$ python3 damage_repair.py --snapshot snap.json --binary /nope --class DC-13bfd302
classes: 1
DC-13bfd302 n= 1 '[[]9,'
$ python3 damage_repair.py --snapshot snap.json --binary /nope --clas DC-13bfd302
classes: 2
DC-13bfd302 n= 1 '[[]9,'
DC-d9efbc31 n= 1 '[[]X",'
exit=0
One character dropped from the flag name, twice the classes processed, exit 0 either way.
Scope
--apply-to writes repaired copies into a scratch tree, so a silently-widened scope currently lands in a scratch directory rather than in specs/, and the tool still never edits the corpus. This is a wrong-and-silent result, not corpus damage.
The same hand-rolled-parser shape is worth checking in the sibling loop tools (damage_freeze.py, damage.py, diffbin.py, cost.py) before fixing just this one; corpus_status.py already uses argparse, which rejects unknown flags for free.
Suggested fix
Reject anything starting with -- that is not a known flag, and reject a known flag whose value is missing, instead of ignoring both. Moving to argparse as corpus_status.py does would cover both cases and remove the hand-rolled loop entirely.
Spotted while fixing #2327 (PR #2338). Filed separately rather than widened into that diff, since it is a distinct defect with a distinct fix.
What
scripts/tri_loop/damage_repair.pyparsesargvby hand and has noelsebranch, so any unrecognised flag is silently ignored and the run continues as if it were not there:The
i + 1 < len(argv)guards have the same shape: a flag given as the last argument, with its value missing, is also ignored rather than rejected.Why it matters
--classnarrows the run to a single damage class. Typo it and the tool repairs every class instead, and exits 0 reporting success — the operator asked for a scoped run and got a corpus-wide one, with no signal that the scope was dropped.Reproduction
Two-class corpus,
damage-repairfromorigin/master:One character dropped from the flag name, twice the classes processed, exit 0 either way.
Scope
--apply-towrites repaired copies into a scratch tree, so a silently-widened scope currently lands in a scratch directory rather than inspecs/, and the tool still never edits the corpus. This is a wrong-and-silent result, not corpus damage.The same hand-rolled-parser shape is worth checking in the sibling loop tools (
damage_freeze.py,damage.py,diffbin.py,cost.py) before fixing just this one;corpus_status.pyalready usesargparse, which rejects unknown flags for free.Suggested fix
Reject anything starting with
--that is not a known flag, and reject a known flag whose value is missing, instead of ignoring both. Moving toargparseascorpus_status.pydoes would cover both cases and remove the hand-rolled loop entirely.