rust-runtime-bug-classes
Skill0 starsChanged 39 days agoMITView on GitHub
Use when writing or reviewing Rust code that touches the filesystem, processes untrusted input, reimplements a Unix CLI, crosses a trust boundary like chroot, or handles bytes that may not be UTF-8 — covers TOCTOU on paths, permission races, OsStr vs String, panic-on-input, silently-discarded errors, NSS/dlopen after chroot, and bug-for-bug compatibility with GNU tools
In this repository66 other files it gives its agents.
- AGENTS.mdAGENTS.md
- postgres-locking-joinsSkill
- ai-bug-patternsSkill
- compressed-ndjson-boundariesSkill
- http-resume-integritySkill
- linux-io-latency-triageSkill
- macos-disk-space-recoverySkill
- minimal-sufficient-evidenceSkill
- modularize-large-filesSkill
- patch-reproducer-validitySkill
- prompt-cache-boundariesSkill
- proton-drive-selective-backupSkill
- transactional-outbox-deliverySkill
- conventional-commitsSkill
- git-advanced-mergingSkill
- git-bisect-forensicsSkill
- git-data-recoverySkill
- git-hooksSkill
- git-rerereSkill
- git-reset-mechanicsSkill
- git-revisions-syntaxSkill
- git-rewriting-historySkill
- git-submodulesSkill
- git-worktreesSkill
- github-ssh-keysSkill
- npm-publish-ci-pitfallsSkill
- sapling-stacked-pr-workflowSkill
- go-concurrency-patternsSkill
- go-data-idiomsSkill
- go-error-handlingSkill
- go-interfaces-embeddingSkill
- go-pprof-profilingSkill
- marketing-funnel-diagnosisSkill
- marketing-geo-experimentsSkill
- marketing-incrementalitySkill
- marketing-positioning-testsSkill
- python-descriptors-mroSkill
- python-logging-cookbookSkill
- python-scaling-regression-testsSkill
- python-unicode-gotchasSkill
- rust-compile-time-invariantsSkill
- rust-deterministic-concurrency-testsSkill
- rust-error-identity-boundariesSkill
- rust-regex-search-contractsSkill
- rust-tokio-actor-deliverySkill
- rust-tokio-cancellation-safetySkill
- sales-discovery-qualificationSkill
- sales-mutual-action-plansSkill
- sales-pipeline-forecast-calibrationSkill
- sales-value-negotiationSkill
- ai-triage-evaluationSkill
- container-image-patchingSkill
- dependency-artifact-integritySkill
- dnssec-sentinel-diagnosticsSkill
- iam-policy-change-replaySkill
- rbvm-applicabilitySkill
- rbvm-asset-evidenceSkill
- rbvm-guarded-remediationSkill
- rbvm-priority-decisionsSkill
- rbvm-risk-exceptionsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
2 rules. About 0 are common, 0 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 41
Use ?, .get(i), checked_add, try_from for expected failures.
- Very specific: line 66
When rewriting coreutils, find, grep, etc., scripts depend on bug-for-bug behavior: exit codes, stderr wording, signal-name parsing (kill …
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Bugs Rust's Type System Won't Catch
Rust prevents memory unsafety and data races, not logic bugs that live in syscalls, encoding, error propagation, or trust boundaries. These are the recurring classes.
Filesystem race & identity bugs
| Bug | Wrong | Right |
TOCTOU between remove_file + create | fs::remove_file(p)?; File::create(p)? | OpenOptions::new().create_new(true).open(p) — atomic, refuses dangling symlinks |
| Default perms then chmod | create_dir(p)?; set_permissions(p, 0o700)? | DirBuilderExt::mode(0o700) / OpenOptions::mode() at creation; set umask explicitly |
| Path equality via string | file == Path::new("/") | fs::canonicalize(file)?; for identity, compare (dev, inode) from MetadataExt |
| Path operations on tainted input | resolving paths repeatedly | Anchor on a file descriptor (e.g. openat, cap-std crate) instead of re-resolving paths |
OsStr / bytes vs String
Filesystem paths and process args are not guaranteed UTF-8 on Unix.
String::from_utf8_lossycorrupts binary streams by replacing bytes withU+FFFD.print!("{}", ...)panics on broken pipe and forces UTF-8.- Stay in bytes:
OsStr,OsString,Path,PathBuf,Vec<u8>,&[u8]. Useio::stdout().write_all(&bytes)for raw output.
Panic-on-input is a DoS
unwrap(), expect(), and indexing can panic when input violates their preconditions. Integer +/- overflow can panic with checks enabled or wrap with checks disabled; never rely on build-profile behavior to reject invalid input. For input-facing crates, configure optional Clippy restrictions in Cargo.toml:
# Cargo.toml (not clippy.toml)
[lints.clippy]
unwrap_used = "warn"
expect_used = "warn"
panic = "warn"
indexing_slicing = "warn"
arithmetic_side_effects = "warn"Use ?, .get(i), checked_add, try_from for expected failures. A justified expect may document an internal invariant whose violation is a bug; explain why input cannot invalidate it. Gallant's panic-boundary discussion distinguishes those bugs from recoverable input errors. Rust's overflow rules remain configuration-sensitive.
Silently discarded errors
file.set_len(size).ok(); // hides ENOSPC
let _ = writeln!(out, "..."); // hides broken pipe
fs::remove_file(p).unwrap_or_default();Propagate. If ignoring is intentional, leave a comment naming the exact errno that's safe. In tools that iterate (e.g. rm -r), track the worst exit code and return it at the end rather than aborting on first failure or losing failures silently.
Trust boundaries: chroot, setuid, sandboxing
NSS (getpwnam, getgrnam, DNS) and other glibc paths dlopen shared libs at call time. After chroot, those loads come from the new root.
let uid = users::get_user_by_name(name); // resolve BEFORE
chroot(new_root)?; // ...then cross the boundaryStatic linking the Rust binary does not prevent glibc from dlopen'ing NSS modules. Resolve users, groups, hostnames, and load any plugins before chroot/setuid/seccomp.
Reimplementing GNU/BSD tools
When rewriting coreutils, find, grep, etc., scripts depend on bug-for-bug behavior: exit codes, stderr wording, signal-name parsing (kill -1 vs kill -SIGHUP), locale-sensitive sort, glob edge cases. Run the upstream test suite in CI; treat behavioral divergence as a bug, not a feature.
Pitfalls
create_new(true)returnsAlreadyExistson dangling symlinks — handle it; don't fall back tocreate()which re-introduces the race.canonicalizerequires the path to exist; for not-yet-created files, canonicalize the parent and join the basename.OsStrhas nolen_charsorcontains(&str)— converting to&strto search reintroduces the UTF-8 assumption you were avoiding.- Clippy
arithmetic_side_effectsflags every+including loop counters; scope it to crates handling untrusted input, not workspace-wide. chrootalone is not a sandbox; combine withsetuidto a non-root user and ideally seccomp/landlock.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

