Skip to content

Commit 5bebbb8

Browse files
authored
Merge pull request #758 from DataDog/jf/K9VULN-8057
[K9VULN-8057] Fix "imports" parser to gracefully handle edge cases
2 parents 11f5395 + 08211ff commit 5bebbb8

File tree

6 files changed

+40
-18
lines changed

6 files changed

+40
-18
lines changed

crates/static-analysis-kernel/src/analysis/ddsa_lib/js/flow/graph.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,9 @@ impl VertexId {
207207

208208
/// Returns the kind of this vertex.
209209
pub fn kind(&self) -> VertexKind {
210-
VertexKind::try_from_id(self.0 & Self::KIND_BIT_MASK)
211-
.expect("js should serialize VertexId correctly")
210+
let kind = VertexKind::try_from_id(self.0 & Self::KIND_BIT_MASK);
211+
debug_assert!(kind.is_ok(), "js should serialize VertexId correctly");
212+
kind.unwrap_or(VertexKind::Invalid)
212213
}
213214

214215
/// Returns the internal node id for this vertex. This will return a [`ddsa_lib::common::NodeId`]
@@ -244,6 +245,7 @@ impl std::fmt::Display for VertexId {
244245
pub enum VertexKind {
245246
Cst = 0,
246247
Phi,
248+
Invalid,
247249
}
248250

249251
impl std::fmt::Display for VertexKind {
@@ -282,6 +284,7 @@ impl VertexKind {
282284
match self {
283285
VertexKind::Cst => Self::CST_STR,
284286
VertexKind::Phi => Self::PHI_STR,
287+
VertexKind::Invalid => "<invalid>",
285288
}
286289
}
287290

@@ -312,7 +315,11 @@ pub(crate) fn id_str(id: &dot_structures::Id) -> Cow<str> {
312315

313316
while let Some(ch) = chars.next() {
314317
unescaped.push(match ch {
315-
'\\' => chars.next().expect("string should never end on `\\`"),
318+
'\\' => {
319+
let next_char = chars.next();
320+
debug_assert!(next_char.is_some(), "string should never end on `\\`");
321+
next_char.unwrap_or_default()
322+
}
316323
_ => ch,
317324
});
318325
}
@@ -854,6 +861,7 @@ graph.adjacencyList;
854861
let js_const = match rust_kind {
855862
VertexKind::Cst => "VERTEX_CST",
856863
VertexKind::Phi => "VERTEX_PHI",
864+
VertexKind::Invalid => unreachable!(),
857865
};
858866
let js_value = try_execute(scope, &format!("{};", js_const)).unwrap();
859867
assert!(js_value.is_number());

crates/static-analysis-kernel/src/analysis/ddsa_lib/js/flow/graph_test_utils.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ impl NodeSearchAttrs {
249249
panic!("phi node: unexpected attribute `{key}`");
250250
}
251251
}
252+
VertexKind::Invalid => unreachable!(),
252253
}
253254
}
254255

@@ -266,6 +267,7 @@ impl NodeSearchAttrs {
266267
}
267268
}
268269
VertexKind::Phi => Self::Phi,
270+
VertexKind::Invalid => unreachable!(),
269271
}
270272
}
271273
}

crates/static-analysis-kernel/src/analysis/ddsa_lib/ops.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ use std::rc::Rc;
1212
#[op2(fast)]
1313
pub fn op_console_push(state: &mut OpState, #[string] line: &str) {
1414
let console = state.borrow::<Rc<RefCell<runtime::JsConsole>>>();
15-
let mut console = console
16-
.try_borrow_mut()
17-
.expect("console should only be accessed via sequential executions");
15+
let Ok(mut console) = console.try_borrow_mut() else {
16+
unreachable!("parallel access of console is impossible");
17+
};
1818
console.push(line);
1919
}
2020

@@ -268,11 +268,12 @@ pub fn op_digraph_adjacency_list_to_dot(
268268
let node_text = ts_node
269269
.utf8_text(text.as_bytes())
270270
.expect("bytes should be utf8 sequence");
271-
LocatedNode::new_cst(ts_node, node_text)
271+
Some(LocatedNode::new_cst(ts_node, node_text))
272272
}
273-
VertexKind::Phi => LocatedNode::new_phi(vid.internal_id()),
273+
VertexKind::Phi => Some(LocatedNode::new_phi(vid.internal_id())),
274+
VertexKind::Invalid => None,
274275
};
275-
Some(located.into())
276+
located.map(Into::into)
276277
};
277278

278279
V8DotGraph::try_new(scope, adjacency_list)

crates/static-analysis-kernel/src/analysis/languages/java/imports.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,23 @@ pub fn parse_imports_with_tree<'text>(
113113
}
114114
}
115115

116-
let package_node = package_node.expect("query invariant: value should be Some");
117-
let target = target.expect("query invariant: value should be Some");
116+
let Some(package_node) = package_node else {
117+
debug_assert!(false, "query invariant: value should be Some");
118+
continue;
119+
};
120+
let Some(target) = target else {
121+
debug_assert!(false, "query invariant: value should be Some");
122+
continue;
123+
};
118124
// Due to the way the tree-sitter-java grammar is defined, when there is an asterisk, what
119125
// we've captured as the `import_child` will represent the full text of the package.
120126
// Otherwise, what we've captured as `package` will.
127+
let Some(import_child_node) = import_child_node else {
128+
debug_assert!(false, "query invariant: value should be Some");
129+
continue;
130+
};
121131
let package = match target {
122-
ImportTarget::Wildcard => {
123-
import_child_node.expect("query invariant: value should be Some")
124-
}
132+
ImportTarget::Wildcard => import_child_node,
125133
ImportTarget::Class(_) => package_node,
126134
};
127135
imports.push(Import { package, target });

crates/static-analysis-kernel/src/analysis/languages/javascript/imports.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,10 @@ pub(crate) fn parse_imports_with_tree_inner<'text>(
216216
name = imported_from.take();
217217
}
218218

219+
debug_assert!(name.is_some(), "name should always be set");
220+
let name = name?;
219221
Some(PackageImport {
220-
name: name.expect("name should always be set"),
222+
name,
221223
imported_from,
222224
})
223225
})

crates/static-analysis-kernel/src/analysis/languages/python/imports.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,10 @@ impl<'a> Import<'a> {
104104
/// from ..common_utils.local_utils import print_array # Some(Import("common_utils"))
105105
/// ```
106106
pub fn parent_import(&self) -> Option<Import<'a>> {
107-
self.full_text.rsplit_once('.').map(|(parent, _)| {
108-
Import::try_new(parent, None, None, self.is_relative)
109-
.expect("full_text should not have whitespace")
107+
self.full_text.rsplit_once('.').and_then(|(parent, _)| {
108+
let import = Import::try_new(parent, None, None, self.is_relative);
109+
debug_assert!(import.is_ok());
110+
import.ok()
110111
})
111112
}
112113
}

0 commit comments

Comments
 (0)