Skip to content

Commit

Permalink
Allow checks for missing require/include files
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Feb 14, 2024
1 parent 8d5bfb9 commit 89c0f01
Show file tree
Hide file tree
Showing 16 changed files with 193 additions and 105 deletions.
16 changes: 8 additions & 8 deletions src/aast_utils/name_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,14 @@ impl NameContext<'_> {
}

match name.as_str() {
"this"
| "static"
| "self"
| "parent"
| "_"
"__FUNCTION__" => return StrId::FUNCTION_CONST,
"__FILE__" => return StrId::FILE_CONST,
"__DIR__" => return StrId::DIR_CONST,
"this" => return StrId::THIS,
"static" => return StrId::STATIC,
"self" => return StrId::SELF,
"parent" => return StrId::PARENT,
"_"
| "__AcceptDisposable"
| "__ConsistentConstruct"
| "__Deprecated"
Expand All @@ -193,9 +196,6 @@ impl NameContext<'_> {
| "__ReturnDisposable"
| "__Sealed"
| "__Soft"
| "__FUNCTION__"
| "__FILE__"
| "__DIR__"
| "__CLASS__" => {
return interner.intern_str(name);
}
Expand Down
2 changes: 1 addition & 1 deletion src/analyzer/expr/assertion_finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ fn scrape_shapes_isset(
if let (Some(shape_name), Some(dim_id)) = (shape_name, dim_id) {
let dict_key = if dim_id.starts_with('\'') {
DictKey::String(dim_id[1..(dim_id.len() - 1)].to_string())
} else if let Ok(arraykey_value) = dim_id.parse::<u32>() {
} else if let Ok(arraykey_value) = dim_id.parse::<u64>() {
DictKey::Int(arraykey_value)
} else {
panic!("bad int key {}", dim_id);
Expand Down
2 changes: 1 addition & 1 deletion src/analyzer/expr/assignment/array_assignment_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ fn update_atomic_given_key(
} => {
let key = match key_value {
TAtomic::TLiteralString { value } => Some(DictKey::String(value.clone())),
TAtomic::TLiteralInt { value } => Some(DictKey::Int(*value as u32)),
TAtomic::TLiteralInt { value } => Some(DictKey::Int(*value as u64)),
TAtomic::TEnumLiteralCase {
enum_name,
member_name,
Expand Down
21 changes: 19 additions & 2 deletions src/analyzer/expr/binop/concat_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use hakana_reflection_info::{
t_atomic::TAtomic,
taint::SinkType,
};
use hakana_type::{get_string, wrap_atomic};
use hakana_type::{get_literal_string, get_string, wrap_atomic};
use oxidized::aast;
use rustc_hash::FxHashSet;

Expand Down Expand Up @@ -63,12 +63,18 @@ pub(crate) fn analyze_concat_nodes(
let mut has_slash = false;
let mut has_query = false;

let mut string_content = Some("".to_string());

for (i, concat_node) in concat_nodes.iter().enumerate() {
if let aast::Expr_::String(simple_string) = &concat_node.2 {
if simple_string == "" {
continue;
}

if let Some(ref mut string_content) = string_content {
*string_content += &simple_string.to_string();
}

if simple_string.contains(&b'/') {
has_slash = true;
}
Expand All @@ -91,6 +97,12 @@ pub(crate) fn analyze_concat_nodes(
if str.contains('?') {
has_query = true;
}

if let Some(ref mut string_content) = string_content {
*string_content += &str;
}
} else {
string_content = None;
}

for old_parent_node in &expr_type.parent_nodes {
Expand All @@ -112,12 +124,17 @@ pub(crate) fn analyze_concat_nodes(
}
} else {
all_literals = false;
string_content = None;
}
}
}

let mut result_type = if all_literals {
wrap_atomic(TAtomic::TStringWithFlags(true, false, true))
if let Some(string_content) = string_content {
get_literal_string(string_content)
} else {
wrap_atomic(TAtomic::TStringWithFlags(true, false, true))
}
} else {
get_string()
};
Expand Down
52 changes: 24 additions & 28 deletions src/analyzer/expr/call/function_call_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use hakana_reflection_info::analysis_result::Replacement;
use hakana_reflection_info::codebase_info::CodebaseInfo;
use hakana_reflection_info::t_atomic::DictKey;
use hakana_reflection_info::t_union::TUnion;
use hakana_reflection_info::{EFFECT_WRITE_LOCAL, EFFECT_WRITE_PROPS, StrId};
use hakana_reflection_info::{StrId, EFFECT_WRITE_LOCAL, EFFECT_WRITE_PROPS};
use hakana_type::type_comparator::union_type_comparator;
use hakana_type::{get_arrayish_params, get_void};
use rustc_hash::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -209,18 +209,16 @@ pub(crate) fn analyze(
context.has_returned = true;
}

let real_name = statements_analyzer.get_interner().lookup(&name);

match real_name {
"HH\\invariant" => {
match name {
StrId::INVARIANT => {
if let Some((_, first_arg)) = &expr.2.first() {
process_invariant(first_arg, context, statements_analyzer, analysis_data);
}
}
"HH\\Lib\\C\\contains_key"
| "HH\\Lib\\Dict\\contains_key"
| "HH\\Lib\\C\\contains"
| "HH\\Lib\\Dict\\contains" => {
StrId::C_CONTAINS
| StrId::C_CONTAINS_KEY
| StrId::DICT_CONTAINS
| StrId::DICT_CONTAINS_KEY => {
let expr_var_id = expression_identifier::get_var_id(
&expr.2[0].1,
context.function_context.calling_class.as_ref(),
Expand All @@ -231,7 +229,7 @@ pub(crate) fn analyze(
)),
);

if real_name == "HH\\Lib\\C\\contains" || real_name == "HH\\Lib\\Dict\\contains" {
if name == StrId::C_CONTAINS || name == StrId::DICT_CONTAINS {
let container_type = analysis_data.get_expr_type(expr.2[0].1.pos()).cloned();
let second_arg_type = analysis_data.get_expr_type(expr.2[1].1.pos()).cloned();
check_array_key_or_value_type(
Expand All @@ -242,12 +240,10 @@ pub(crate) fn analyze(
second_arg_type,
pos,
false,
&real_name.to_string(),
name,
&context.function_context.calling_functionlike_id,
);
} else if real_name == "HH\\Lib\\C\\contains_key"
|| real_name == "HH\\Lib\\Dict\\contains_key"
{
} else {
let container_type = analysis_data.get_expr_type(expr.2[0].1.pos()).cloned();

if let Some(expr_var_id) = expr_var_id {
Expand All @@ -266,7 +262,7 @@ pub(crate) fn analyze(
FxHashMap::from_iter([(
expr_var_id.clone(),
vec![Assertion::HasArrayKey(DictKey::Int(
boxed.parse::<u32>().unwrap(),
boxed.parse::<u64>().unwrap(),
))],
)]),
);
Expand Down Expand Up @@ -298,7 +294,7 @@ pub(crate) fn analyze(
Some(second_arg_type.clone()),
pos,
true,
&real_name.to_string(),
name,
&context.function_context.calling_functionlike_id,
);
}
Expand Down Expand Up @@ -331,7 +327,7 @@ pub(crate) fn analyze(
}
}
}
"HH\\Lib\\Str\\starts_with" => {
StrId::STR_STARTS_WITH => {
if expr.2.len() == 2 {
if let GraphKind::WholeProgram(_) = &analysis_data.data_flow_graph.kind {
let expr_var_id = expression_identifier::get_var_id(
Expand Down Expand Up @@ -373,7 +369,7 @@ pub(crate) fn analyze(
}
}
}
"HH\\Lib\\Regex\\matches" => {
StrId::REGEX_MATCHES => {
if expr.2.len() == 2 {
if let GraphKind::WholeProgram(_) = &analysis_data.data_flow_graph.kind {
let expr_var_id = expression_identifier::get_var_id(
Expand All @@ -396,17 +392,18 @@ pub(crate) fn analyze(
if let Some(str) = second_arg_type.get_single_literal_string_value() {
let mut hashes_to_remove = FxHashSet::default();

if str.starts_with('^') && str != "^http:\\/\\/"
&& str != "^https:\\/\\/" && str != "^https?:\\/\\/" {
if str.starts_with('^')
&& str != "^http:\\/\\/"
&& str != "^https:\\/\\/"
&& str != "^https?:\\/\\/"
{
hashes_to_remove.extend([
SinkType::HtmlAttributeUri,
SinkType::CurlUri,
SinkType::RedirectUri,
]);

if str.ends_with('$')
&& !str.contains(".*")
&& !str.contains(".+")
if str.ends_with('$') && !str.contains(".*") && !str.contains(".+")
{
hashes_to_remove.extend([
SinkType::HtmlTag,
Expand Down Expand Up @@ -434,7 +431,7 @@ pub(crate) fn analyze(
}
}
}
"HH\\Asio\\join" => {
StrId::ASIO_JOIN => {
if context.inside_async {
let issue = Issue::new(
IssueKind::NoJoinInAsyncFunction,
Expand Down Expand Up @@ -518,8 +515,7 @@ fn process_invariant(
active_type_assertions,
context,
&mut changed_var_ids,
&assert_type_assertions.keys().cloned()
.collect(),
&assert_type_assertions.keys().cloned().collect(),
statements_analyzer,
analysis_data,
first_arg.pos(),
Expand Down Expand Up @@ -548,7 +544,7 @@ fn check_array_key_or_value_type(
arg_type: Option<TUnion>,
pos: &Pos,
is_key: bool,
function_name: &String,
function_name: StrId,
calling_functionlike_id: &Option<FunctionLikeIdentifier>,
) {
let mut has_valid_container_type = false;
Expand All @@ -574,7 +570,7 @@ fn check_array_key_or_value_type(
} else {
error_message = Some(format!(
"Second arg of {} expects type {}, saw {}",
function_name,
statements_analyzer.get_interner().lookup(&function_name),
param.get_id(Some(statements_analyzer.get_interner())),
arg_type.get_id(Some(statements_analyzer.get_interner()))
));
Expand Down
Loading

0 comments on commit 89c0f01

Please sign in to comment.