Skip to content

Commit

Permalink
Merge branch 'fix_extension_loaded' into fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
danog committed Oct 19, 2023
2 parents 89ec7dd + 576e4d2 commit 692d4f4
Show file tree
Hide file tree
Showing 45 changed files with 743 additions and 139 deletions.
13 changes: 10 additions & 3 deletions dictionaries/CallMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -12886,10 +12886,16 @@
'str_contains' => ['bool', 'haystack'=>'string', 'needle'=>'string'],
'str_ends_with' => ['bool', 'haystack'=>'string', 'needle'=>'string'],
'str_getcsv' => ['non-empty-list<?string>', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'],
'str_ireplace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'],
'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'],
'str_replace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_rot13' => ['string', 'string'=>'string'],
'str_shuffle' => ['string', 'string'=>'string'],
'str_split' => ['list<non-empty-string>', 'string'=>'string', 'length='=>'positive-int'],
Expand Down Expand Up @@ -13015,7 +13021,8 @@
'substr' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'],
'substr_compare' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'?int', 'case_insensitive='=>'bool'],
'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'?int'],
'substr_replace' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'],
'suhosin_get_raw_cookies' => ['array'],
'SVM::__construct' => ['void'],
Expand Down
8 changes: 6 additions & 2 deletions dictionaries/CallMap_80_delta.php
Original file line number Diff line number Diff line change
Expand Up @@ -2589,8 +2589,12 @@
'new' => ['string', 'string'=>'string', 'offset'=>'int', 'length='=>'?int'],
],
'substr_replace' => [
'old' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
'old' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
],
'substr_replace\'1' => [
'old' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'new' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]|null'],
],
'tidy_parse_file' => [
'old' => ['tidy', 'filename'=>'string', 'config='=>'array|string', 'encoding='=>'string', 'useIncludePath='=>'bool'],
Expand Down
13 changes: 10 additions & 3 deletions dictionaries/CallMap_historical.php
Original file line number Diff line number Diff line change
Expand Up @@ -14303,10 +14303,16 @@
'stomp_unsubscribe' => ['bool', 'link'=>'resource', 'destination'=>'string', 'headers='=>'?array'],
'stomp_version' => ['string'],
'str_getcsv' => ['non-empty-list<?string>', 'string'=>'string', 'separator='=>'string', 'enclosure='=>'string', 'escape='=>'string'],
'str_ireplace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_ireplace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_ireplace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_ireplace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_pad' => ['string', 'string'=>'string', 'length'=>'int', 'pad_string='=>'string', 'pad_type='=>'int'],
'str_repeat' => ['string', 'string'=>'string', 'times'=>'int'],
'str_replace' => ['string|string[]', 'search'=>'string|array', 'replace'=>'string|array', 'subject'=>'string|array', '&w_count='=>'int'],
'str_replace' => ['string', 'search'=>'string', 'replace'=>'string', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'1' => ['string[]', 'search'=>'string', 'replace'=>'string', 'subject'=>'array', '&w_count='=>'int'],
'str_replace\'2' => ['string', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'string', '&w_count='=>'int'],
'str_replace\'3' => ['string[]', 'search'=>'array', 'replace'=>'string|string[]', 'subject'=>'array', '&w_count='=>'int'],
'str_rot13' => ['string', 'string'=>'string'],
'str_shuffle' => ['string', 'string'=>'string'],
'str_split' => ['non-empty-list<string>', 'string'=>'string', 'length='=>'positive-int'],
Expand Down Expand Up @@ -14430,7 +14436,8 @@
'substr' => ['string|false', 'string'=>'string', 'offset'=>'int', 'length='=>'int'],
'substr_compare' => ['int|false', 'haystack'=>'string', 'needle'=>'string', 'offset'=>'int', 'length='=>'int', 'case_insensitive='=>'bool'],
'substr_count' => ['int', 'haystack'=>'string', 'needle'=>'string', 'offset='=>'int', 'length='=>'int'],
'substr_replace' => ['string|string[]', 'string'=>'string|string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'substr_replace' => ['string', 'string'=>'string', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'substr_replace\'1' => ['string[]', 'string'=>'string[]', 'replace'=>'string|string[]', 'offset'=>'int|int[]', 'length='=>'int|int[]'],
'suhosin_encrypt_cookie' => ['string|false', 'name'=>'string', 'value'=>'string'],
'suhosin_get_raw_cookies' => ['array'],
'svm::crossvalidate' => ['float', 'problem'=>'array', 'number_of_folds'=>'int'],
Expand Down
3 changes: 2 additions & 1 deletion dictionaries/ImpureFunctionsList.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
'socket_set_block' => true,
'socket_set_nonblock' => true,
'socket_listen' => true,
'stream_socket_shutdown' => true,
'socket_shutdown' => true,
// meta calls
'call_user_func' => true,
'call_user_func_array' => true,
Expand All @@ -93,7 +95,6 @@
'mcrypt_generic_deinit' => true,
'mcrypt_module_close' => true,
// internal optimisation
'opcache_compile_file' => true,
'clearstatcache' => true,
// process-related
'pcntl_signal' => true,
Expand Down
1 change: 1 addition & 0 deletions docs/security_analysis/custom_taint_sources.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class BadSqlTainter implements AfterExpressionAnalysisInterface
);
}
}
return null;
}
}
```
4 changes: 4 additions & 0 deletions src/Psalm/Internal/Analyzer/ClassLikeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ public static function checkFullyQualifiedClassLikeName(
?string $calling_method_id,
array $suppressed_issues,
?ClassLikeNameOptions $options = null,
bool $check_classes = true
): ?bool {
if ($options === null) {
$options = new ClassLikeNameOptions();
Expand Down Expand Up @@ -278,6 +279,9 @@ public static function checkFullyQualifiedClassLikeName(
&& !($interface_exists && $options->allow_interface)
&& !($enum_exists && $options->allow_enum)
) {
if (!$check_classes) {
return null;
}
if (!$options->allow_trait || !$codebase->classlikes->traitExists($fq_class_name, $code_location)) {
if ($options->from_docblock) {
if (IssueBuffer::accepts(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ public static function verifyReturnType(
)
)
&& !$return_type->isVoid()
&& !$return_type->isNever()
&& !$inferred_yield_types
&& (!$function_like_storage || !$function_like_storage->has_yield)
&& $function_returns_implicitly
Expand All @@ -224,7 +225,7 @@ public static function verifyReturnType(
) {
if (IssueBuffer::accepts(
new InvalidReturnType(
$cased_method_id . ' is not expected to return any values but it does, '
$cased_method_id . ' is not expected to return, but it does, '
. 'either implicitly or explicitly',
$return_type_location,
),
Expand Down
11 changes: 11 additions & 0 deletions src/Psalm/Internal/Analyzer/FunctionLikeAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,17 @@ private function processParams(
);
}

if ($param_type->isNever()) {
IssueBuffer::maybeAdd(
new ReservedWord(
'Parameter cannot be never',
$function_param->type_location,
'never',
),
$this->suppressed_issues,
);
}

if ($param_type->check(
$this->source,
$function_param->type_location,
Expand Down
10 changes: 10 additions & 0 deletions src/Psalm/Internal/Analyzer/MethodComparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@ private static function checkForObviousMethodMismatches(
);
}

if ($guide_method_storage->returns_by_ref && !$implementer_method_storage->returns_by_ref) {
IssueBuffer::maybeAdd(
new MethodSignatureMismatch(
'Method ' . $cased_implementer_method_id . ' must return by-reference',
$code_location,
),
$suppressed_issues + $implementer_classlike_storage->suppressed_issues,
);
}

if ($guide_method_storage->external_mutation_free
&& !$implementer_method_storage->external_mutation_free
&& !$guide_method_storage->mutation_free_inferred
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -671,16 +671,14 @@ private static function analyzeAssignment(
return false;
}

if ($context->check_classes) {
if (StaticPropertyAssignmentAnalyzer::analyze(
$statements_analyzer,
$assign_var,
$assign_value,
$assign_value_type,
$context,
) === false) {
return false;
}
if (StaticPropertyAssignmentAnalyzer::analyze(
$statements_analyzer,
$assign_var,
$assign_value,
$assign_value_type,
$context,
) === false) {
return false;
}

if ($var_id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use Psalm\Type\Union;
use UnexpectedValueException;

use function array_merge;
use function in_array;
use function strlen;

Expand Down Expand Up @@ -172,6 +173,14 @@ public static function analyze(
$removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event);

if ($stmt_left_type && $stmt_left_type->parent_nodes) {
// numeric types can't be tainted html or has_quotes, neither can bool
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $stmt_left_type->isSingle()
&& ($stmt_left_type->isInt() || $stmt_left_type->isFloat() || $stmt_left_type->isBool())
) {
$removed_taints = array_merge($removed_taints, array('html', 'has_quotes'));
}

foreach ($stmt_left_type->parent_nodes as $parent_node) {
$statements_analyzer->data_flow_graph->addPath(
$parent_node,
Expand All @@ -184,6 +193,14 @@ public static function analyze(
}

if ($stmt_right_type && $stmt_right_type->parent_nodes) {
// numeric types can't be tainted html or has_quotes, neither can bool
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $stmt_right_type->isSingle()
&& ($stmt_right_type->isInt() || $stmt_right_type->isFloat() || $stmt_right_type->isBool())
) {
$removed_taints = array_merge($removed_taints, array('html', 'has_quotes'));
}

foreach ($stmt_right_type->parent_nodes as $parent_node) {
$statements_analyzer->data_flow_graph->addPath(
$parent_node,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Union;

use function array_merge;
use function count;
use function explode;
use function implode;
Expand Down Expand Up @@ -1483,19 +1484,19 @@ private static function processTaintedness(
return;
}

// numeric types can't be tainted, neither can bool
$event = new AddRemoveTaintsEvent($expr, $context, $statements_analyzer, $codebase);

$added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event);
$removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event);

// numeric types can't be tainted html or has_quotes, neither can bool
if ($statements_analyzer->data_flow_graph instanceof TaintFlowGraph
&& $input_type->isSingle()
&& ($input_type->isInt() || $input_type->isFloat() || $input_type->isBool())
) {
return;
$removed_taints = array_merge($removed_taints, array('html', 'has_quotes'));
}

$event = new AddRemoveTaintsEvent($expr, $context, $statements_analyzer, $codebase);

$added_taints = $codebase->config->eventDispatcher->dispatchAddTaints($event);
$removed_taints = $codebase->config->eventDispatcher->dispatchRemoveTaints($event);

if ($function_param->type && $function_param->type->isString() && !$input_type->isString()) {
$input_type = CastAnalyzer::castStringAttempt(
$statements_analyzer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class AtomicMethodCallAnalysisResult
public array $invalid_method_call_types = [];

/**
* @var array<string>
* @var array<string, bool>
*/
public array $existent_method_ids = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ public static function analyze(
$context->calling_method_id,
$statements_analyzer->getSuppressedIssues(),
new ClassLikeNameOptions(true, false, true, true, $lhs_type_part->from_docblock),
$context->check_classes,
);
}

Expand Down Expand Up @@ -340,7 +341,7 @@ public static function analyze(
$all_intersection_return_type = null;
$all_intersection_existent_method_ids = [];

// insersection types are also fun, they also complicate matters
// intersection types are also fun, they also complicate matters
if ($intersection_types) {
[$all_intersection_return_type, $all_intersection_existent_method_ids]
= self::getIntersectionReturnType(
Expand Down Expand Up @@ -527,7 +528,7 @@ public static function analyze(
/**
* @param TNamedObject|TTemplateParam $lhs_type_part
* @param array<string, Atomic> $intersection_types
* @return array{?Union, array<string>}
* @return array{?Union, array<string, bool>}
*/
private static function getIntersectionReturnType(
StatementsAnalyzer $statements_analyzer,
Expand Down Expand Up @@ -648,7 +649,8 @@ private static function handleInvalidClass(
&& $stmt->name instanceof PhpParser\Node\Identifier
&& isset($lhs_type_part->methods[strtolower($stmt->name->name)])
) {
$result->existent_method_ids[] = $lhs_type_part->methods[strtolower($stmt->name->name)];
$method_id = $lhs_type_part->methods[strtolower($stmt->name->name)];
$result->existent_method_ids[$method_id] = true;
} elseif (!$is_intersection) {
if ($stmt->name instanceof PhpParser\Node\Identifier) {
$codebase->analyzer->addMixedMemberName(
Expand Down Expand Up @@ -917,7 +919,7 @@ private static function handleCallableObject(
?TemplateResult $inferred_template_result = null,
): void {
$method_id = 'object::__invoke';
$result->existent_method_ids[] = $method_id;
$result->existent_method_ids[$method_id] = true;
$result->has_valid_method_call_type = true;

if ($lhs_type_part_callable !== null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ public static function analyze(

$cased_method_id = $fq_class_name . '::' . $stmt_name->name;

$result->existent_method_ids[] = $method_id->__toString();

$result->existent_method_ids[$method_id->__toString()] = true;

if ($context->collect_initializations && $context->calling_method_id) {
[$calling_method_class] = explode('::', $context->calling_method_id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static function handleMagicMethod(
if ($stmt->isFirstClassCallable()) {
if (isset($class_storage->pseudo_methods[$method_name_lc])) {
$result->has_valid_method_call_type = true;
$result->existent_method_ids[] = $method_id->__toString();
$result->existent_method_ids[$method_id->__toString()] = true;
$result->return_type = self::createFirstClassCallableReturnType(
$class_storage->pseudo_methods[$method_name_lc],
);
Expand Down Expand Up @@ -112,7 +112,7 @@ public static function handleMagicMethod(

if ($found_method_and_class_storage) {
$result->has_valid_method_call_type = true;
$result->existent_method_ids[] = $method_id->__toString();
$result->existent_method_ids[$method_id->__toString()] = true;

[$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage;

Expand Down Expand Up @@ -200,7 +200,7 @@ public static function handleMagicMethod(
}

$result->has_valid_method_call_type = true;
$result->existent_method_ids[] = $method_id->__toString();
$result->existent_method_ids[$method_id->__toString()] = true;

$array_values = array_map(
static fn(PhpParser\Node\Arg $arg): PhpParser\Node\Expr\ArrayItem => new VirtualArrayItem(
Expand Down Expand Up @@ -237,7 +237,7 @@ public static function handleMagicMethod(
}

/**
* @param array<string> $all_intersection_existent_method_ids
* @param array<string, bool> $all_intersection_existent_method_ids
*/
public static function handleMissingOrMagicMethod(
StatementsAnalyzer $statements_analyzer,
Expand Down Expand Up @@ -269,7 +269,7 @@ public static function handleMissingOrMagicMethod(
&& $found_method_and_class_storage
) {
$result->has_valid_method_call_type = true;
$result->existent_method_ids[] = $method_id->__toString();
$result->existent_method_ids[$method_id->__toString()] = true;

[$pseudo_method_storage, $defining_class_storage] = $found_method_and_class_storage;

Expand Down
Loading

0 comments on commit 692d4f4

Please sign in to comment.