aya: return errors instead of panicking on invalid CString inputs#1560
aya: return errors instead of panicking on invalid CString inputs#1560surno wants to merge 5 commits into
Conversation
✅ Deploy Preview for aya-rs-docs ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
There was a previous attempt at this in #1389. Could you please consider those review comments and confirm that those comments do not apply here? Thanks for your contribution. |
120f10b to
1ec80f7
Compare
Thanks. I went through #1389 and here's how I mapped each comment to this PR:
Addressed. Updated the name from error -> source.
Already done. All path fields use
Compled. See maps/info:120 , programs/info.rs:227, programs/links:351, programs/mod.rs:623
Already done. Single commit.
Completed. Every new variant has
Kept the fully qualified name to keep the diff scoped. I can update the call sites and drop the fully qualified name at each point, if you prefer.
I did not change the
That comment was on A couple of additional notes:
|
tamird
left a comment
There was a problem hiding this comment.
That comment was on
MapError::InvalidNameataya/src/maps/mod.rs:612, which this PR doesn't touch. I agree the variant should either beInvalidPathor carry a#[source]for the droppedNulError. Happy to follow up in another PR.
The pre-existing
PinError::InvalidPinPathataya/src/pin.rsstill useserror: NulError. Aligning it tosourceis a breaking pattern-match change unrelated to the TODO cleanup, so I left it for a follow-up. Let me know if you'd prefer it bundled.
I would prefer these changes in this PR but in separate commits. Thanks for your contribution!
@tamird reviewed 9 files and all commit messages, and made 3 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on surno).
aya/src/programs/tc.rs line 315 at r1 (raw file):
I did not change the
TcErrorShape, this is a separate issue out of scope of this PR. Happy to do a follow up PR.
Would you mind making this a second commit in this PR? I think it's useful to look at the API shape all at once.
aya/src/programs/xdp.rs line 108 at r1 (raw file):
unknown interface seems misleading
It puts the
NulErrorinto the existingUnknownInterfacesince a nul-containing wouldn't exist anyways.
That's true, but perhaps misleading. IMO it'd be better to add a variant.
1ec80f7 to
953e8bf
Compare
surno
left a comment
There was a problem hiding this comment.
@surno made 2 comments.
Reviewable status: 3 of 10 files reviewed, 2 unresolved discussions (waiting on tamird).
aya/src/programs/tc.rs line 315 at r1 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
I did not change the
TcErrorShape, this is a separate issue out of scope of this PR. Happy to do a follow up PR.Would you mind making this a second commit in this PR? I think it's useful to look at the API shape all at once.
Done with two commits. On MapError::InvalidName, the input there is the map name, not a path, so I kept the variant InvalidName and added the source: NulError field instead. Please let me know if you'd like it renamed.
aya/src/programs/xdp.rs line 108 at r1 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
unknown interface seems misleading
It puts the
NulErrorinto the existingUnknownInterfacesince a nul-containing wouldn't exist anyways.That's true, but perhaps misleading. IMO it'd be better to add a variant.
Updated with a separate invariant, ProgramError::InvalidInterfaceName to signal to callers that the name itself was incorrect.
tamird
left a comment
There was a problem hiding this comment.
@codex review
@tamird reviewed 7 files and all commit messages, made 1 comment, and resolved 2 discussions.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on surno).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0dea8b8210
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| #[source] | ||
| /// The source error. | ||
| error: std::ffi::NulError, | ||
| source: std::ffi::NulError, |
There was a problem hiding this comment.
Restore PinError::InvalidPinPath
error field name
Renaming PinError::InvalidPinPath from error to source is a public API break for downstream exhaustive pattern matches and struct-variant field access. The commit message explicitly says this rename was intentionally avoided, so the code now contradicts stated intent and semver notes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Probably should update the commit message.
There was a problem hiding this comment.
Thanks for pointing this out. Turns out it was because the PR didn't match the commit. I didn't updated the line in the PR which claimed it was avoided while the commits on the stack did update it after initial review.
.
There was a problem hiding this comment.
Pull request overview
This PR eliminates several CString::new(...).unwrap() panic sites across aya by mapping NulError into typed error variants, so invalid inputs (interior NUL bytes) are reported as normal errors instead of crashing callers.
Changes:
- Introduces new error variants to surface invalid pin paths, tracepoint names, and interface names as typed errors (instead of panics).
- Reshapes
TcError::NulErrorinto a struct variant that includes the rejected TC name and the underlyingNulError. - Updates API snapshots to reflect the resulting public API changes.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| xtask/public-api/aya.txt | Updates the public API snapshot to include the new/reshaped error variants and fields. |
| aya/src/programs/xdp.rs | Converts interface name CString creation from unwrap() to ProgramError::InvalidInterfaceName. |
| aya/src/programs/tc.rs | Reworks TC NUL handling to return TcError::NulError { name, source } instead of panicking. |
| aya/src/programs/raw_trace_point.rs | Converts tracepoint name CString creation from unwrap() to ProgramError::InvalidTracepointName. |
| aya/src/programs/mod.rs | Adds ProgramError::InvalidPinPath and uses it in program loading-from-pin path conversion. |
| aya/src/programs/links.rs | Adds LinkError::InvalidPinPath and uses it in PinnedLink::from_pin path conversion. |
| aya/src/programs/info.rs | Uses ProgramError::InvalidPinPath when loading program info from a pinned path. |
| aya/src/pin.rs | Renames PinError::InvalidPinPath field to source and marks it as #[source]. |
| aya/src/maps/mod.rs | Adds MapError::InvalidPinPath, augments MapError::InvalidName with a source, and updates path/name conversions. |
| aya/src/maps/info.rs | Uses MapError::InvalidPinPath when loading map info from a pinned path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// The path for the BPF object is not valid. | ||
| #[error("invalid pin path `{}`", path.display())] | ||
| InvalidPinPath { | ||
| /// The path. | ||
| path: std::path::PathBuf, | ||
|
|
||
| #[source] | ||
| /// The source error. | ||
| error: std::ffi::NulError, | ||
| source: std::ffi::NulError, | ||
| }, |
| /// Invalid map name encountered | ||
| #[error("invalid map name `{name}`")] | ||
| InvalidName { | ||
| /// The map name | ||
| name: String, | ||
| #[source] | ||
| /// The source error. | ||
| source: std::ffi::NulError, | ||
| }, |
| // try to open map in case it's already pinned | ||
| let path = path.as_ref(); | ||
| let path_string = match CString::new(path.as_os_str().as_bytes()) { | ||
| Ok(path) => path, | ||
| Err(error) => { | ||
| Err(source) => { | ||
| return Err(MapError::PinError { | ||
| name: Some(name.into()), | ||
| error: PinError::InvalidPinPath { | ||
| path: path.to_path_buf(), | ||
| error, | ||
| source, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
This comment seem worth addressing.
There was a problem hiding this comment.
Addressed.
MapData::from_pin and MapData::create_pinned_by_name now return a MapError::InvalidPinPath { path, soruce }
| error, | ||
| source, | ||
| }, | ||
| })?; |
There was a problem hiding this comment.
Addressed.
MapData::from_pin and MapData::create_pinned_by_name now return a MapError::InvalidPinPath { path, soruce }
tamird
left a comment
There was a problem hiding this comment.
@tamird made 3 comments.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on alessandrod and surno).
| #[source] | ||
| /// The source error. | ||
| error: std::ffi::NulError, | ||
| source: std::ffi::NulError, |
There was a problem hiding this comment.
Probably should update the commit message.
| // try to open map in case it's already pinned | ||
| let path = path.as_ref(); | ||
| let path_string = match CString::new(path.as_os_str().as_bytes()) { | ||
| Ok(path) => path, | ||
| Err(error) => { | ||
| Err(source) => { | ||
| return Err(MapError::PinError { | ||
| name: Some(name.into()), | ||
| error: PinError::InvalidPinPath { | ||
| path: path.to_path_buf(), | ||
| error, | ||
| source, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
This comment seem worth addressing.
| error, | ||
| source, | ||
| }, | ||
| })?; |
Five call sites converted user-provided byte sequences into a CString
via `.unwrap()`, which would panic if the input contained an interior
nul byte. Replace each with proper error returns.
Pattern A — path → CString (4 sites):
- `ProgramData::from_pinned_path`, `ProgramInfo::from_pin`,
`PinnedLink::from_pin`, and `MapInfo::from_pin` now surface a new
`InvalidPinPath { path, source }` variant on `ProgramError`,
`LinkError`, and `MapError` respectively. The variants mirror the
existing `PinError::InvalidPinPath` used on the pin (write) side.
- `MapData::create_pinned_by_name` and `MapData::from_pin` previously
surfaced the same condition wrapped as `MapError::PinError { error:
PinError::InvalidPinPath { .. }, .. }`. They now return
`MapError::InvalidPinPath` directly so the same invalid-path
condition surfaces under the same variant from every call site.
Pattern B — name → CString (1 site):
- `RawTracePoint::attach` now returns a new
`ProgramError::InvalidTracepointName { name, source }` variant
instead of unwrapping. This site had an unmarked `.unwrap()` not
flagged by a `// TODO`, but is in the same family as the path
conversions and was picked up from aya-rs#1389's coverage.
The new variants are not `#[non_exhaustive]`, matching the surrounding
enums. Per Cargo's SemVer guide this is a major change for downstream
callers that exhaustively `match` on these errors; consistent with how
variants are added elsewhere in this repo.
- In TcError, the NulError variant has been expanded to include the offending TC program name which contains an unexpected nul byte with the source error. - In SchedClassifier::do_attach and SchedClassifier::qdisc_detach_program, adds the name of the offending TC name in the new NulError variant. Per Cargo's SemVer guide this is a major change for callers that destructure or construct TcError::NulError (tuple → struct variant); consistent with how variants are reshaped elsewhere in this repo.
0dea8b8 to
1607287
Compare
surno
left a comment
There was a problem hiding this comment.
@surno made 5 comments and resolved 2 discussions.
Reviewable status: 3 of 10 files reviewed, 3 unresolved discussions (waiting on alessandrod and tamird).
| #[source] | ||
| /// The source error. | ||
| error: std::ffi::NulError, | ||
| source: std::ffi::NulError, |
There was a problem hiding this comment.
Thanks for pointing this out. Turns out it was because the PR didn't match the commit. I didn't updated the line in the PR which claimed it was avoided while the commits on the stack did update it after initial review.
.
| /// The path for the BPF object is not valid. | ||
| #[error("invalid pin path `{}`", path.display())] | ||
| InvalidPinPath { | ||
| /// The path. | ||
| path: std::path::PathBuf, | ||
|
|
||
| #[source] | ||
| /// The source error. | ||
| error: std::ffi::NulError, | ||
| source: std::ffi::NulError, | ||
| }, |
| /// Invalid map name encountered | ||
| #[error("invalid map name `{name}`")] | ||
| InvalidName { | ||
| /// The map name | ||
| name: String, | ||
| #[source] | ||
| /// The source error. | ||
| source: std::ffi::NulError, | ||
| }, |
| // try to open map in case it's already pinned | ||
| let path = path.as_ref(); | ||
| let path_string = match CString::new(path.as_os_str().as_bytes()) { | ||
| Ok(path) => path, | ||
| Err(error) => { | ||
| Err(source) => { | ||
| return Err(MapError::PinError { | ||
| name: Some(name.into()), | ||
| error: PinError::InvalidPinPath { | ||
| path: path.to_path_buf(), | ||
| error, | ||
| source, | ||
| }, | ||
| }); |
There was a problem hiding this comment.
Addressed.
MapData::from_pin and MapData::create_pinned_by_name now return a MapError::InvalidPinPath { path, soruce }
| error, | ||
| source, | ||
| }, | ||
| })?; |
There was a problem hiding this comment.
Addressed.
MapData::from_pin and MapData::create_pinned_by_name now return a MapError::InvalidPinPath { path, soruce }
tamird
left a comment
There was a problem hiding this comment.
@codex review
@tamird reviewed 7 files and all commit messages, made 1 comment, and resolved 3 discussions.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on alessandrod).
|
Codex Review: Didn't find any major issues. Delightful! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
| /// The program is not attached. | ||
| #[error("the program name `{name}` is invalid")] | ||
| InvalidName { | ||
| /// program name | ||
| name: String, | ||
| }, |
There was a problem hiding this comment.
Looks right but preexisting. Would be good to fix in another commit or PR.
| /// If the given `interface` name is malformed | ||
| /// [`ProgramError::InvalidInterfaceName`] is returned. |
- Adds a new `ProgramError::InvalidInterfaceName` error variant to report when name is malformed with unexpected nul byte sequence - removes unwrap used for reporting nul byte error on the interface name Per Cargo's SemVer guide adding a variant to a non-#[non_exhaustive] enum is a major change for callers that exhaustively match on ProgramError; consistent with how variants are added elsewhere in this repo.
- Aligns with the source field name used by the new variants in
"aya: return errors instead of panicking on invalid CString inputs"
and with the conventional thiserror naming.
This is a SemVer-major change for callers that destructure
PinError::InvalidPinPath { error, .. }.
- The CString::new failure at MapData::create previously discarded
the underlying NulError. Marking it as #[source] so error reporters
can walk the chain.
Per Cargo's SemVer guide this is a major change for callers that
destructure MapError::InvalidName { name } (now requires
{ name, source } or { name, .. }); consistent with how struct
variants are extended elsewhere in this repo.
1607287 to
3672dc8
Compare
surno
left a comment
There was a problem hiding this comment.
@surno resolved 2 discussions.
Reviewable status: 4 of 10 files reviewed, all discussions resolved (waiting on alessandrod and tamird).
|
Apologies for the latency; this needs a rebase now. |
Summary
Resolves the six
// TODO: avoid this unwrap by adding a new error variantsites scattered across aya, and aligns the resulting error-variant shape
across the four enums that gained an
InvalidPinPathvariant. The unwrapswould panic if a caller passed a path or name containing an interior nul
byte; this PR converts each into a typed error. Picks up the work from
#1389 (stalled since April) and applies the review feedback from that
thread.
Approach
Five commits, each scoped to one concern:
aya: return errors instead of panicking on invalid CString inputsInvalidPinPath { path, source }variants to
ProgramError,LinkError, andMapError, mirroring theexisting
PinError::InvalidPinPathinaya/src/pin.rs.RawTracePoint::attachuses a newProgramError::InvalidTracepointNamevariant. (This site had anunmarked
.unwrap()not flagged by a TODO, but in the same family —caught from Fix TODOs of unwrap calls by implementing Error Variants #1389's coverage.)
aya: report invalid TC name in NulError variantTcError::NulErrorfrom a tuple variant intoNulError { name, source }, so callers can see which TC name wasrejected. Updates
SchedClassifier::do_attachandqdisc_detach_programto populate the new field.aya: ProgramError::InvalidInterfaceName error variantProgramError::InvalidInterfaceName { name, source }for
Xdp::attach, instead of folding the failure into the pre-existingUnknownInterfacevariant.aya: rename PinError::InvalidPinPath field error to sourcePinError::InvalidPinPathusederror: NulError.With the new sibling variants in commits 1–3 settling on
source: NulError(matching thiserror conventions and Fix TODOs of unwrap calls by implementing Error Variants #1389's reviewfeedback), this commit aligns the original to avoid a permanent
inconsistency across the four parallel
InvalidPinPathvariants.aya: include NulError source in MapError::InvalidNameMapData::creatediscarded the underlyingNulErrorwhen the mapname failed conversion. Adds a
source: NulErrorfield toMapError::InvalidNameso error reporters can walk the chain,matching the source-handling pattern used elsewhere in this PR.
SemVer notes
These are breaking changes for downstream callers that exhaustively match
on the affected enums. Per Cargo's SemVer guide
they are technically major, though consistent with how variants are added
elsewhere in this repo:
InvalidPinPath,InvalidTracepointName,InvalidInterfaceName) toProgramError,LinkError, andMapError(none of which are
#[non_exhaustive]).TcError::NulErrorfrom a tuple variant to a struct variant.PinError::InvalidPinPath's fielderror→source.sourcefield toMapError::InvalidName.cargo xtask public-apisnapshot updated accordingly.Tests
I considered adding unit tests for the new error variants but did not see
precedent for testing similar variants (e.g.
PinError::InvalidPinPath,ProgramError::InvalidName). Happy to add them if you'd like.Test plan
cargo checkcargo +nightly fmt --all -- --checkcargo clippy -p aya --all-targets -- -D warningscargo test -p aya --lib(134 passing)cargo xtask public-api(snapshot updated)This change is