Skip to content

Commit

Permalink
Enforce literal string length limit
Browse files Browse the repository at this point in the history
Fixes #9376

Ensures:
* that we never have a literal string exceeding the length limit
* that we call string interpreter for all literal strings
  • Loading branch information
weirdan committed Feb 23, 2023
1 parent e96a929 commit 5dec7f3
Show file tree
Hide file tree
Showing 21 changed files with 119 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
use Psalm\Type\Atomic\TLiteralClassString;
use Psalm\Type\Atomic\TLiteralFloat;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TObjectWithProperties;
Expand Down Expand Up @@ -536,7 +535,7 @@ private static function handleUnpackedArray(
continue 2;
}
$new_offset = $key;
$array_creation_info->item_key_atomic_types[] = new TLiteralString($new_offset);
$array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset);
$array_creation_info->all_list = false;
} else {
$new_offset = $array_creation_info->int_offset++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,10 @@ public static function updateArrayType(
$key_values = [];

if ($current_dim instanceof PhpParser\Node\Scalar\String_) {
$key_values[] = new TLiteralString($current_dim->value);
$value_type = Type::getAtomicStringFromLiteral($current_dim->value);
if ($value_type instanceof TLiteralString) {
$key_values[] = $value_type;
}
} elseif ($current_dim instanceof PhpParser\Node\Scalar\LNumber && !$root_is_string) {
$key_values[] = new TLiteralInt($current_dim->value);
} elseif ($current_dim
Expand Down Expand Up @@ -330,7 +333,7 @@ private static function updateTypeWithKeyValues(
$v = $type->value;
$v[0] = $new_char;
$changed = true;
$type = new TLiteralString($v);
$type = Type::getAtomicStringFromLiteral($v);
break;
}
}
Expand Down Expand Up @@ -1036,7 +1039,10 @@ private static function getDimKeyValues(
$key_values = [];

if ($dim instanceof PhpParser\Node\Scalar\String_) {
$key_values[] = new TLiteralString($dim->value);
$value_type = Type::getAtomicStringFromLiteral($dim->value);
if ($value_type instanceof TLiteralString) {
$key_values[] = $value_type;
}
} elseif ($dim instanceof PhpParser\Node\Scalar\LNumber) {
$key_values[] = new TLiteralInt($dim->value);
} else {
Expand Down Expand Up @@ -1077,7 +1083,10 @@ private static function getArrayAssignmentOffsetType(
&& $child_stmt_dim_type->isSingleStringLiteral())
) {
if ($child_stmt->dim instanceof PhpParser\Node\Scalar\String_) {
$offset_type = new TLiteralString($child_stmt->dim->value);
$offset_type = Type::getAtomicStringFromLiteral($child_stmt->dim->value);
if (!$offset_type instanceof TLiteralString) {
return [null, '[string]', false];
}
} else {
$offset_type = $child_stmt_dim_type->getSingleStringLiteral();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
use Psalm\Type\Atomic\TFalse;
use Psalm\Type\Atomic\TFloat;
use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TLowercaseString;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString;
Expand Down Expand Up @@ -173,7 +172,7 @@ public static function analyze(
break 2;
}

$result_type_parts[] = new TLiteralString($literal);
$result_type_parts[] = Type::getAtomicStringFromLiteral($literal);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static function analyze(
if ($type_part instanceof TLiteralInt) {
$type_part = new TLiteralInt(~$type_part->value);
} elseif ($type_part instanceof TLiteralString) {
$type_part = new TLiteralString(~$type_part->value);
$type_part = Type::getAtomicStringFromLiteral(~$type_part->value);
}

$acceptable_types[] = $type_part;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
use Psalm\Type\Atomic\TKeyedArray;
use Psalm\Type\Atomic\TList;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyArray;
use Psalm\Type\Atomic\TNull;
Expand Down Expand Up @@ -80,7 +79,7 @@ public static function fetch(
if ($stmt->isFirstClassCallable()) {
$candidate_callable = CallableTypeComparator::getCallableFromAtomic(
$codebase,
new TLiteralString($function_id),
Type::getAtomicStringFromLiteral($function_id),
null,
$statements_analyzer,
true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
use Psalm\Type\Atomic\TDependentGetType;
use Psalm\Type\Atomic\TFloat;
use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TLowercaseString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
Expand Down Expand Up @@ -625,17 +624,17 @@ private static function handleDependentTypeFunction(
$class_string_types[] = new TClassString();
} else {
if ($class_type instanceof TInt) {
$class_string_types[] = new TLiteralString('int');
$class_string_types[] = Type::getAtomicStringFromLiteral('int');
} elseif ($class_type instanceof TString) {
$class_string_types[] = new TLiteralString('string');
$class_string_types[] = Type::getAtomicStringFromLiteral('string');
} elseif ($class_type instanceof TFloat) {
$class_string_types[] = new TLiteralString('float');
$class_string_types[] = Type::getAtomicStringFromLiteral('float');
} elseif ($class_type instanceof TBool) {
$class_string_types[] = new TLiteralString('bool');
$class_string_types[] = Type::getAtomicStringFromLiteral('bool');
} elseif ($class_type instanceof TClosedResource) {
$class_string_types[] = new TLiteralString('resource (closed)');
$class_string_types[] = Type::getAtomicStringFromLiteral('resource (closed)');
} elseif ($class_type instanceof TNull) {
$class_string_types[] = new TLiteralString('null');
$class_string_types[] = Type::getAtomicStringFromLiteral('null');
} else {
$class_string_types[] = new TString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ public static function castStringAttempt(
|| $atomic_type instanceof TNumeric
) {
if ($atomic_type instanceof TLiteralInt || $atomic_type instanceof TLiteralFloat) {
$castable_types[] = new TLiteralString((string) $atomic_type->value);
$castable_types[] = Type::getAtomicStringFromLiteral((string) $atomic_type->value);
} elseif ($atomic_type instanceof TNonspecificLiteralInt) {
$castable_types[] = new TNonspecificLiteralString();
} else {
Expand All @@ -740,20 +740,20 @@ public static function castStringAttempt(
if ($atomic_type instanceof TNull
|| $atomic_type instanceof TFalse
) {
$valid_strings[] = new TLiteralString('');
$valid_strings[] = Type::getAtomicStringFromLiteral('');
continue;
}

if ($atomic_type instanceof TTrue
) {
$valid_strings[] = new TLiteralString('1');
$valid_strings[] = Type::getAtomicStringFromLiteral('1');
continue;
}

if ($atomic_type instanceof TBool
) {
$valid_strings[] = new TLiteralString('1');
$valid_strings[] = new TLiteralString('');
$valid_strings[] = Type::getAtomicStringFromLiteral('1');
$valid_strings[] = Type::getAtomicStringFromLiteral('');
continue;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Psalm\Internal\Analyzer\StatementsAnalyzer;
use Psalm\Internal\DataFlow\DataFlowNode;
use Psalm\Plugin\EventHandler\Event\AddRemoveTaintsEvent;
use Psalm\Type;
use Psalm\Type\Atomic\TLiteralFloat;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
Expand Down Expand Up @@ -123,7 +124,7 @@ public static function analyze(
if ($non_empty) {
if ($literal_string !== null) {
$stmt_type = new Union(
[new TLiteralString($literal_string)],
[Type::getAtomicStringFromLiteral($literal_string)],
['parent_nodes' => $parent_nodes],
);
} elseif ($all_literals) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,10 @@ public static function getArrayAccessTypeGivenOffset(
$key_values = [];

if ($stmt->dim instanceof PhpParser\Node\Scalar\String_) {
$key_values[] = new TLiteralString($stmt->dim->value);
$value_type = Type::getAtomicStringFromLiteral($stmt->dim->value);
if ($value_type instanceof TLiteralString) {
$key_values[] = $value_type;
}
} elseif ($stmt->dim instanceof PhpParser\Node\Scalar\LNumber) {
$key_values[] = new TLiteralInt($stmt->dim->value);
} elseif ($stmt->dim && ($stmt_dim_type = $statements_analyzer->node_data->getType($stmt->dim))) {
Expand Down Expand Up @@ -514,7 +517,7 @@ public static function getArrayAccessTypeGivenOffset(

if ($in_assignment) {
$offset_type->removeType('null');
$offset_type->addType(new TLiteralString(''));
$offset_type->addType(Type::getAtomicStringFromLiteral(''));
}
}

Expand All @@ -534,7 +537,7 @@ public static function getArrayAccessTypeGivenOffset(
$offset_type->removeType('null');

if (!$offset_type->ignore_nullable_issues) {
$offset_type->addType(new TLiteralString(''));
$offset_type->addType(Type::getAtomicStringFromLiteral(''));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
use Psalm\Type\Atomic\TGenericObject;
use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNull;
Expand Down Expand Up @@ -935,7 +934,7 @@ private static function handleEnumName(
if ($lhs_type_part instanceof TEnumCase) {
$statements_analyzer->node_data->setType(
$stmt,
new Union([new TLiteralString($lhs_type_part->case_name)]),
new Union([Type::getAtomicStringFromLiteral($lhs_type_part->case_name)]),
);
} else {
$statements_analyzer->node_data->setType($stmt, Type::getNonEmptyString());
Expand Down Expand Up @@ -971,7 +970,7 @@ private static function handleEnumValue(

foreach ($enum_cases as $enum_case) {
if (is_string($enum_case->value)) {
$case_values[] = new TLiteralString($enum_case->value);
$case_values[] = Type::getAtomicStringFromLiteral($enum_case->value);
} elseif (is_int($enum_case->value)) {
$case_values[] = new TLiteralInt($enum_case->value);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,7 @@ private static function handleUnpackedArray(
foreach ($unpacked_atomic_type->properties as $key => $property_value) {
if (is_string($key)) {
$new_offset = $key;
$array_creation_info->item_key_atomic_types[] = new TLiteralString($new_offset);
$array_creation_info->item_key_atomic_types[] = Type::getAtomicStringFromLiteral($new_offset);
} else {
$new_offset = $array_creation_info->int_offset++;
$array_creation_info->item_key_atomic_types[] = new TLiteralInt($new_offset);
Expand Down
4 changes: 2 additions & 2 deletions src/Psalm/Internal/Codebase/ConstantTypeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public static function resolve(
|| $right instanceof TLiteralFloat
|| $right instanceof TLiteralInt)
) {
return new TLiteralString($left->value . $right->value);
return Type::getAtomicStringFromLiteral($left->value . $right->value);
}

return new TString();
Expand Down Expand Up @@ -355,7 +355,7 @@ public static function getLiteralTypeFromScalarValue($value): Atomic
}

if (is_string($value)) {
return new TLiteralString($value);
return Type::getAtomicStringFromLiteral($value);
}

if (is_int($value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,10 @@ public function start(PhpParser\Node\Stmt\ClassLike $node): ?bool
$name_types = [];
$values_types = [];
foreach ($storage->enum_cases as $name => $enumCaseStorage) {
$name_types[] = new Type\Atomic\TLiteralString($name);
$name_types[] = Type::getAtomicStringFromLiteral($name);
if ($storage->enum_type !== null) {
if (is_string($enumCaseStorage->value)) {
$values_types[] = new Type\Atomic\TLiteralString($enumCaseStorage->value);
$values_types[] = Type::getAtomicStringFromLiteral($enumCaseStorage->value);
} elseif (is_int($enumCaseStorage->value)) {
$values_types[] = new Type\Atomic\TLiteralInt($enumCaseStorage->value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static function getGetObjectVarsReturnType(
$object_type = reset($atomics);

if ($object_type instanceof Atomic\TEnumCase) {
$properties = ['name' => new Union([new Atomic\TLiteralString($object_type->case_name)])];
$properties = ['name' => new Union([Type::getAtomicStringFromLiteral($object_type->case_name)])];
$codebase = $statements_source->getCodebase();
$enum_classlike_storage = $codebase->classlike_storage_provider->get($object_type->value);
if ($enum_classlike_storage->enum_type === null) {
Expand All @@ -66,7 +66,7 @@ public static function getGetObjectVarsReturnType(
if (is_int($enum_case_storage->value)) {
$properties['value'] = new Union([new Atomic\TLiteralInt($enum_case_storage->value)]);
} elseif (is_string($enum_case_storage->value)) {
$properties['value'] = new Union([new Atomic\TLiteralString($enum_case_storage->value)]);
$properties['value'] = new Union([Type::getAtomicStringFromLiteral($enum_case_storage->value)]);
}
return new TKeyedArray($properties);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Psalm\Type;
use Psalm\Type\Atomic\TBool;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Union;

Expand Down Expand Up @@ -42,20 +41,20 @@ public static function getFunctionReturnType(FunctionReturnTypeProviderEvent $ev
if ($operator_type) {
if (!$operator_type->hasMixed()) {
$acceptable_operator_type = new Union([
new TLiteralString('<'),
new TLiteralString('lt'),
new TLiteralString('<='),
new TLiteralString('le'),
new TLiteralString('>'),
new TLiteralString('gt'),
new TLiteralString('>='),
new TLiteralString('ge'),
new TLiteralString('=='),
new TLiteralString('='),
new TLiteralString('eq'),
new TLiteralString('!='),
new TLiteralString('<>'),
new TLiteralString('ne'),
Type::getAtomicStringFromLiteral('<'),
Type::getAtomicStringFromLiteral('lt'),
Type::getAtomicStringFromLiteral('<='),
Type::getAtomicStringFromLiteral('le'),
Type::getAtomicStringFromLiteral('>'),
Type::getAtomicStringFromLiteral('gt'),
Type::getAtomicStringFromLiteral('>='),
Type::getAtomicStringFromLiteral('ge'),
Type::getAtomicStringFromLiteral('=='),
Type::getAtomicStringFromLiteral('='),
Type::getAtomicStringFromLiteral('eq'),
Type::getAtomicStringFromLiteral('!='),
Type::getAtomicStringFromLiteral('<>'),
Type::getAtomicStringFromLiteral('ne'),
]);

$codebase = $statements_source->getCodebase();
Expand Down
10 changes: 5 additions & 5 deletions src/Psalm/Internal/Type/SimpleNegatedAssertionReconciler.php
Original file line number Diff line number Diff line change
Expand Up @@ -987,17 +987,17 @@ private static function reconcileFalsyOrEmpty(

if (get_class($string_atomic_type) === TString::class) {
$existing_var_type->removeType('string');
$existing_var_type->addType(new TLiteralString(''));
$existing_var_type->addType(new TLiteralString('0'));
$existing_var_type->addType(Type::getAtomicStringFromLiteral(''));
$existing_var_type->addType(Type::getAtomicStringFromLiteral('0'));
} elseif (get_class($string_atomic_type) === TNonEmptyString::class) {
$existing_var_type->removeType('string');
$existing_var_type->addType(new TLiteralString('0'));
$existing_var_type->addType(Type::getAtomicStringFromLiteral('0'));
} elseif (get_class($string_atomic_type) === TNonEmptyLowercaseString::class) {
$existing_var_type->removeType('string');
$existing_var_type->addType(new TLiteralString('0'));
$existing_var_type->addType(Type::getAtomicStringFromLiteral('0'));
} elseif (get_class($string_atomic_type) === TNonEmptyNonspecificLiteralString::class) {
$existing_var_type->removeType('string');
$existing_var_type->addType(new TLiteralString('0'));
$existing_var_type->addType(Type::getAtomicStringFromLiteral('0'));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Psalm/Internal/Type/TypeCombiner.php
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ private static function getArrayTypeFromGenericParams(
} elseif ($type instanceof TKeyedArray && isset($type->class_strings[$property_name])) {
$objectlike_keys[$property_name] = new TLiteralClassString($property_name, $from_docblock);
} else {
$objectlike_keys[$property_name] = new TLiteralString($property_name, $from_docblock);
$objectlike_keys[$property_name] = Type::getAtomicStringFromLiteral($property_name, $from_docblock);
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/Psalm/Internal/Type/TypeParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
use Psalm\Type\Atomic\TLiteralClassString;
use Psalm\Type\Atomic\TLiteralFloat;
use Psalm\Type\Atomic\TLiteralInt;
use Psalm\Type\Atomic\TLiteralString;
use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyArray;
Expand Down Expand Up @@ -393,7 +392,7 @@ public static function getTypeFromTree(
}

if ($parse_tree->value[0] === '"' || $parse_tree->value[0] === '\'') {
return new TLiteralString(substr($parse_tree->value, 1, -1), $from_docblock);
return Type::getAtomicStringFromLiteral(substr($parse_tree->value, 1, -1), $from_docblock);
}

if (strpos($parse_tree->value, '::')) {
Expand Down
Loading

0 comments on commit 5dec7f3

Please sign in to comment.