Skip to content

Commit 9a0bf0d

Browse files
committed
Audit panics
1 parent ad569e6 commit 9a0bf0d

12 files changed

Lines changed: 92 additions & 60 deletions

File tree

src/pdo/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,15 @@ impl From<u32> for PdoKind {
5454

5555
impl From<u8> for PdoKind {
5656
fn from(value: u8) -> Self {
57+
// NOTE: If this mask changes, the panic safety comment below must be reevaluated
5758
const PDO_KIND_MASK: u8 = 0x3;
5859
match value & PDO_KIND_MASK {
5960
0x0 => PdoKind::Fixed,
6061
0x1 => PdoKind::Battery,
6162
0x2 => PdoKind::Variable,
6263
0x3 => PdoKind::Augmented,
64+
// Panic safety: This will never panic if the mask above does not change
65+
#[allow(clippy::unreachable)]
6366
_ => unreachable!(),
6467
}
6568
}

src/pdo/rdo.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@ pub enum Rdo {
2222

2323
impl Rdo {
2424
/// Create a new RDO from the raw data and the corresponding PDO
25-
pub fn for_pdo(rdo: u32, pdo: impl Common) -> Self {
26-
match pdo.kind() {
25+
///
26+
/// Returns `None` if `pdo` does not contain an APDO kind
27+
pub fn for_pdo(rdo: u32, pdo: impl Common) -> Option<Self> {
28+
Some(match pdo.kind() {
2729
PdoKind::Fixed => Rdo::Fixed(FixedVarRaw(rdo).into()),
2830
PdoKind::Variable => Rdo::Variable(FixedVarRaw(rdo).into()),
2931
PdoKind::Battery => Rdo::Battery(BatteryRaw(rdo).into()),
30-
PdoKind::Augmented => match pdo.apdo_kind().unwrap() {
32+
PdoKind::Augmented => match pdo.apdo_kind()? {
3133
ApdoKind::SprPps => Rdo::Pps(PpsRaw(rdo).into()),
3234
ApdoKind::EprAvs => Rdo::Pps(PpsRaw(rdo).into()),
3335
ApdoKind::SprAvs => Rdo::Avs(AvsRaw(rdo).into()),
3436
},
35-
}
37+
})
3638
}
3739
}
3840

@@ -375,7 +377,8 @@ mod tests {
375377
voltage_mv: 0,
376378
operational_current_ma: 0,
377379
}),
378-
);
380+
)
381+
.unwrap();
379382
let expected = Rdo::Fixed(FixedVarData {
380383
object_position: 3,
381384
capability_mismatch: true,
@@ -401,7 +404,8 @@ mod tests {
401404
min_voltage_mv: 0,
402405
operational_current_ma: 0,
403406
}),
404-
);
407+
)
408+
.unwrap();
405409
let expected = Rdo::Variable(FixedVarData {
406410
object_position: 3,
407411
capability_mismatch: true,
@@ -427,7 +431,8 @@ mod tests {
427431
min_voltage_mv: 0,
428432
operational_power_mw: 0,
429433
}),
430-
);
434+
)
435+
.unwrap();
431436
let expected = Rdo::Battery(BatteryData {
432437
object_position: 3,
433438
capability_mismatch: true,
@@ -453,7 +458,8 @@ mod tests {
453458
min_voltage_mv: 0,
454459
max_current_ma: 0,
455460
})),
456-
);
461+
)
462+
.unwrap();
457463
let expected = Rdo::Pps(PpsData {
458464
object_position: 3,
459465
capability_mismatch: true,
@@ -478,7 +484,8 @@ mod tests {
478484
max_current_15v_ma: 0,
479485
max_current_20v_ma: 0,
480486
})),
481-
);
487+
)
488+
.unwrap();
482489
let expected = Rdo::Avs(AvsData {
483490
object_position: 3,
484491
capability_mismatch: true,

src/pdo/sink.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,15 @@ pub enum FrsRequiredCurrent {
152152

153153
impl From<u8> for FrsRequiredCurrent {
154154
fn from(value: u8) -> Self {
155+
// NOTE: If this mask changes, the panic safety comment below must be reevaluated
155156
const FRS_REQUIRED_CURRENT_MASK: u8 = 0x3;
156157
match value & FRS_REQUIRED_CURRENT_MASK {
157158
0 => FrsRequiredCurrent::None,
158159
1 => FrsRequiredCurrent::Default,
159160
2 => FrsRequiredCurrent::Current1A5,
160161
3 => FrsRequiredCurrent::Current3A,
162+
// Panic safety: This will never panic if the mask above does not change
163+
#[allow(clippy::unreachable)]
161164
_ => unreachable!(),
162165
}
163166
}

src/pdo/source.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,17 @@ pub enum PeakCurrent {
146146
Pct150,
147147
}
148148

149-
const PEAK_CURRENT_MASK: u8 = 0x3;
150149
impl From<u8> for PeakCurrent {
151150
fn from(value: u8) -> Self {
151+
// NOTE: If this mask changes, the panic safety comment below must be reevaluated
152+
const PEAK_CURRENT_MASK: u8 = 0x3;
152153
match value & PEAK_CURRENT_MASK {
153154
0x0 => PeakCurrent::Pct100,
154155
0x1 => PeakCurrent::Pct110,
155156
0x2 => PeakCurrent::Pct125,
156157
0x3 => PeakCurrent::Pct150,
158+
// Panic safety: This will never panic if the mask above does not change
159+
#[allow(clippy::unreachable)]
157160
_ => unreachable!(),
158161
}
159162
}

src/ucsi/lpm/get_alternate_modes.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,8 @@ impl defmt::Format for ArgsRaw {
5353
pub struct Args(ArgsRaw);
5454

5555
impl Args {
56-
pub fn recipient(&self) -> Recipient {
57-
let recipient: Result<Recipient, _> = self.0.recipient().try_into();
58-
// Won't panic, validated in try_from
59-
recipient.unwrap()
56+
pub fn recipient(&self) -> Result<Recipient, InvalidRecipient> {
57+
self.0.recipient().try_into()
6058
}
6159

6260
pub fn set_recipient(&mut self, recipient: Recipient) -> &mut Self {

src/ucsi/lpm/get_cable_property.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ impl From<u16> for SpeedSupported {
6868
0x1 => SpeedSupported::Kbps(raw.value()),
6969
0x2 => SpeedSupported::Mbps(raw.value()),
7070
0x3 => SpeedSupported::Gbps(raw.value()),
71+
// Panic safety: `units` is constrained to 2 bits via bitfield so this will never panic
72+
#[allow(clippy::unreachable)]
7173
_ => unreachable!(),
7274
}
7375
}
@@ -126,6 +128,8 @@ impl From<u8> for PlugEndType {
126128
0x1 => PlugEndType::TypeB,
127129
0x2 => PlugEndType::TypeC,
128130
0x3 => PlugEndType::Other,
131+
// Panic safety: This is trivially guaranteed to not panic
132+
#[allow(clippy::unreachable)]
129133
_ => unreachable!(),
130134
}
131135
}

src/ucsi/lpm/get_connector_status.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,8 +704,11 @@ impl From<ResponseData> for [u8; RESPONSE_DATA_LEN] {
704704
raw.set_partner_flags(status.partner_flags.into());
705705
raw.set_partner_type(status.partner_type as u8);
706706

707-
if status.rdo.is_some_and(|rdo| rdo != 0) {
708-
raw.set_rdo(status.rdo.unwrap());
707+
// Note: Can be collapsed to a let chain when this crate is updated to 2024 edition
708+
if let Some(rdo) = status.rdo {
709+
if rdo != 0 {
710+
raw.set_rdo(rdo)
711+
}
709712
}
710713

711714
if let Some(battery_charging_status) = status.battery_charging_status {

src/ucsi/lpm/get_pdos.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,8 @@ impl Args {
171171
self
172172
}
173173

174-
pub fn source_capability_type(&self) -> SourceCapabilityType {
175-
// Won't panic, validated in try_from
176-
self.0.source_capability_type().try_into().unwrap()
174+
pub fn source_capability_type(&self) -> Result<SourceCapabilityType, InvalidSourceCapabilityType> {
175+
self.0.source_capability_type().try_into()
177176
}
178177

179178
pub fn set_source_capability_type(&mut self, source_capabilities_type: SourceCapabilityType) -> &mut Self {
@@ -227,13 +226,19 @@ pub struct ResponseData {
227226
impl ResponseData {
228227
/// Iterator over valid PDOs
229228
pub fn iter(&self) -> impl ExactSizeIterator<Item = u32> + '_ {
229+
// NOTE: If this changes the panic safety comment below should be revisited
230230
let last_pdo = self.raw.iter().position(|&pdo| pdo == 0).unwrap_or(self.raw.len());
231+
// Panic safety: `last_pdo` will always be in bounds
232+
#[allow(clippy::indexing_slicing)]
231233
self.raw.as_slice()[..last_pdo].iter().copied()
232234
}
233235

234236
/// Mutable iterator over valid PDOs
235237
pub fn iter_mut(&mut self) -> impl ExactSizeIterator<Item = &mut u32> + '_ {
238+
// NOTE: If this changes the panic safety comment below should be revisited
236239
let last_pdo = self.raw.iter().position(|&pdo| pdo == 0).unwrap_or(self.raw.len());
240+
// Panic safety: `last_pdo` will always be in bounds
241+
#[allow(clippy::indexing_slicing)]
237242
self.raw.as_mut_slice()[..last_pdo].iter_mut()
238243
}
239244
}

src/ucsi/lpm/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,11 @@ impl<T: PortId> Encode for Command<T> {
198198

199199
impl<T: PortId> Decode<CommandHeader> for Command<T> {
200200
fn decode<D: Decoder<Context = CommandHeader>>(decoder: &mut D) -> Result<Self, DecodeError> {
201-
match decoder.context().command() {
201+
match decoder
202+
.context()
203+
.command()
204+
.map_err(|_| DecodeError::Other("Invalid command"))?
205+
{
202206
CommandType::ConnectorReset => {
203207
let connector_number = ConnectorNumberRaw::decode(decoder)?.connector_number();
204208
// Don't actually have any args, but need to consume command padding

src/ucsi/lpm/set_power_level.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,8 @@ impl Args {
135135
}
136136
}
137137

138-
pub fn type_c_current(&self) -> Current {
139-
let current: Result<Current, _> = Current::try_from(self.0.type_c_current());
140-
current.unwrap() // Won't panic, validated in try_from
138+
pub fn type_c_current(&self) -> Result<Current, InvalidCurrent> {
139+
Current::try_from(self.0.type_c_current())
141140
}
142141

143142
pub fn set_type_c_current(&mut self, type_c_current: Current) -> &mut Self {

0 commit comments

Comments
 (0)