We have a number of "types" like integer which are not actually
supported as builtin types -- instead they are silently interpreted
as class types.
I've seen this cause confusion a few types already. This change adds
a warning in this case. In the unlikely case that someone legitimately
wants to type against an integer class, the warning can be suppressed
by writing \integer or "use integer", or using Integer (this warning
will only trigger for lowercase spellings).
Closes GH-4815.
* Change a number of "resource used as offset" notices to warnings,
which were previously missed.
* Throw the "resource used as offset" warning for isset() as well.
* Make array_key_exists() behavior with regard to different key
types consistent with isset() and normal array accesses. All key
types now use the usual coercions and array/object keys throw
TypeError.
Closes GH-4887.
This reverts commit edccf32f7f.
This was reported to cause issues for as yet unknown reasons in
bug #78769. As this was intended as code cleanup, revert this from
7.4 at least. May reapply it to master later.
Since `zend_parse_parameters()` throws now, there is no reason to
explicitly call `zend_parse_parameters_throw()` anymore, and since both
have actually the same implementation, we redefine the latter as macro.
These were checking whether the instruction set is supported by
the host CPU, however they were only used to condition on whether
this instruction set is targeted at all. It would still use dynamic
dispatch (e.g. based on ifunc resolvers) to select the actual
implementation. Whether the target is guaranteed to support the
instruction set without dispatch is determined based on pre-defined
macros like __SSE2__.
This removes the configure-time builtin cpu checks to remove
confusion. Additionally this allows targeting an architecture that
is newer than the host architecture.
We are now guaranteed that $this always exists inside methods, as
well as insides closures (if they use $this at all).
This removes checks for $this existence from the individual object
opcodes. Instead ZEND_FETCH_THIS is used in the cases where $this
is not guaranteed to exist, which is mainly the pseudo-main scope.
Closes GH-3822.
NULL out the execute_data before destroying it, otherwise GC may
trigger while the execute_data is partially destroyed, resulting
in double-frees.
The handling of call stack unfreezing is a bit awkward because it's
a ZEND_API function, so we can't change the signature.
Assigning to an uninitialized typed property will no longer trigger
a call to __set(). However, calls to __set() are still triggered if
the property is explicitly unset().
This gives us both the behavior people generally expect, and still
allows ORMs to do lazy initialization by unsetting properties.
For PHP 8, we should fine a way to forbid unsetting of declared
properties entirely, and provide a different way to achieve lazy
initialization.
Split out the simple equality check into an inline function --
this is one of the common cases.
Replace instanceof_function_ex with zend_class_implements_interface.
There are a few more places where it may be used.
Parent interfaces are copied into the interface list during
inheritance, so there's no need to perform a recursive check.
Only exception are instanceof checks performed during inheritance
itself. However, we already have unlinked_instanceof for this
purpose, it just needs to be taught to handle this case.
Closes GH-4857.
instanceof_class does not need to check for a NULL pointer in the
first iteration -- passing NULL to this function is illegal.
instanceof_interface does not need to use instanceof_class(), it
only has to check whether the CEs match exactly. There is no way
for an interface to appear inside "parent", it will always be in
"interfaces" only.
The instanceof_interface_only() function was dead code (always
returned zero).
Clarify that the last parameter indicates whether the passed CE
is interface or class and rewrite the code in terms of assertions.
Noticed while working on union types: We do not load argument and
return types during type checks, but we do load property types.
I'm normalizing the behavior towards the existing status quo (not
loading), though we may consider loading everywhere (all types,
and instanceof) in order to properly support class aliases.
Add deprecated _ZendTestClass::__toString() method to preserve
an existing test.
ReflectionType::__toString() will now return a complete
representation of the type, as it should have originally. Users
that relied on nullability being absent should have been pushed
to ReflectionNamedType::getName() by the deprecation of
ReflectionType::__toString() in PHP 7.1 / PHP 7.4.
Property types are invariant, but may still have to load classes in
order to check for class aliases. This class loading should follow
the same rules as all other variance checks, rather than just
loading unconditionally.
This change integrates property type invariance checks into the
variance system as a new obligation type, and prevent early binding
if the type check cannot be performed.
We also change `Generator::throw()` to expect a `Throwable` in the
first place, and we now throw a TypeError instead of returning `false`
from `Exception::getTraceAsString()`.
This goes in the reverse direction of 4463acb951.
After looking around a bit, it seems that we already check for
Z_ISERROR_P() on the get_property_ptr_ptr return value in other places.
So do this in zend_fetch_property_address() as well, and also make
sure that EG(error_zval) is indeed returned on exception in
get_property_ptr_ptr.
In particular, this fixes the duplicate exceptions that we used to
get because first get_property_ptr_ptr threw one and then
read_property throws the same exception again.
Relying on setting ERROR if an exception happened during the
property address fetch is both a bit fragile and may pessimize
other codepaths that will check for exceptions in the VM. Adding
an extra exception check instead, which should also allow us to
drop the use of ERROR in this area in master.
Avoid need of insertion NOP opcoes between unrelated SMART BRANCH instruction and following JMPZ/JMPNZ.
Now instead of checking the opcode of following instruction, the same information is encoded into SMART BRANH result_type.
After fixing the int->double coercion case, this is already verified
at compile-time, so there is no need to redo this type check on
every call.
Only perform the type check every time for the case of AST default
values.
Previously if the "non well formed" notice was converted into an
exception we'd still end up executing the function.
Also drop the now unnecessary EG(exception) checks in the engine.
Additionally remote a bogus exception in zend_is_callable: It
should only be writing to error, but not directly throwing.
Make sure the initialize the result of FETCH_OBJ_UNSET operations.
I'm using a NULL value rather than ERROR here, because the latter
no longer exists in master.
Usually it will already fail when opening, but reads can also
fail since PHP 7.4, in which case we still need to place the
file handle in open_files to make sure the destructor will run
on it.
* get_parent_class() argument is optional
* Mark array_filter() $callback as optional
* The $base of gmp_strval() is optional
* DateTime constructor also accepts zero arguments
* hash_update_file() stream context is optional
* xmlwriter_write_dtd_entity() $isparam argument is optional
This originally manifested as a leak in oss-fuzz #18000. The following
is a reduced test case:
<?php
[
5 => 1,
"foo" > 1,
" " => "" == 0
];
<<<BAR
$x
BAR;
Because this particular error condition did not return T_ERROR,
EG(exception) was set while performing binary operation constant
evaluation, which checks exceptions for cast failures.
Instead of adding this indirect test case, I'm adding an assertion
that the lexer has to return T_ERROR if EG(exception) is set.
I'm going for a very conservative fix here, where the previous
logic is restored for the case where an object is passed to
method_exists(). We might want to check against EG(scope) instead,
but this seems like a safer choice.
This means that behavior in PHP 7.4 changes only for
method_exists('C', 'privateMethodNotOnC'), which should be sensible.
Not NULLing the static_variables pointer for shadow methods during
static var shutdown would be a way to avoid this leak, but unless
there's evidence that inherited private methods with static vars are
actually a common use-case, I don't think we should keep this kind
of fragile edge-case optimization.
Fixes OSS-Fuzz #17875.
It is now only used to signal exceptions for property reads. ERROR
zvals are never returned back to the VM anymore, so there's no
need to check for them when receiving a VAR.
Also return MAY_BE_ERROR, as ERROR is now no longer relevant for
inference.
Weirdly these warnings had zero coverage previously...
Remove an incorrect exception checking optimization: The key
lookup may throw (it could also throw previously, though only
through a custom error handler).
Resources used as array keys are generally handled by throwing a
notice and converting the resource to the resource handle. The only
exception is the [$resource => null] syntax, where this was treated
as an illegal offset type instead. However, this also only happened
for VM evaluations, the AST evaluator did handle resources correctly.
This removes object auto-vivification support.
This also means that we can remove the corresponding special
handling for typed properites: We no longer need to check that a
property is convertible to stdClass if such a conversion might
take place indirectly due to a nested property write.
Additionally OBJ_W style operations now no longer modify the
object operand, and as such we no longer need to treat op1 as a
def in SSA form.
The next step would be to actually compile the whole LHS of OBJ_W
operations in R rather than W mode, but that causes issues with
SimpleXML, whose object handlers depend on the current compilation
structure.
Part of https://wiki.php.net/rfc/engine_warnings.
`get_closure` handlers are called to check whether an object is
callable, and to actually get the closure, respectively. The behavior
of the handler might differ for these two cases, particularly the
handler may throw in the latter case, but should not in the former.
Therefore we add a `check_only` parameter, to be able to distinguish
the desired purpose.
Use value 0 instead. To compensate we check in ReflectionParameter
allowsNull() whether the type is set at all: If it isn't, it always
allows null.
This removes a discrepancy between internal&userland functions:
For userland functions allowsNull() on untyped parameters returned
true, but for internal functions it returned false.
We have lots of other typed properties related error messages of
the form "assign X to typed property Y::$z of type A", so use th
same format for the primary message as well. Special-casing things
like classes and nullability is not going to scale with future
type-system extensions, and I don't think it really adds clarity
either.
This switches zend_type from storing a single IS_* type code to
storing a MAY_BE_* type mask. Right now most code still assumes
that there is only a single type in the mask (or two together
with MAY_BE_NULL). But this will make it a lot simpler to introduce
union types.
An additional advantage (and why I'm doing this separately), is
that a number of special cases no longer need to be handled
separately: We can do a single mask & (1 << type) check to handle
all simple types, booleans (true|false) and null.
To clean up the mess here a bit, check for invalid octal digits
with an explicit loop instead of mixing this into the string to
number conversion.
Also clean up some type usage.
This makes sure that we use compiler builtins when they are
available and thus avoid ubsan warnings in clang.
And also reindent the fallback implementation.
zend_emit_op_data may reallocate the op_array, so the assignment
of the RETURNS_FUNCTION flag may happen on an outdated opline.
Restructure the code a bit to set the flag before calling
zend_emit_op_data().
This is a fix for symfony/symfony#32995.
The behavior is:
* Throwing exception when loading parent/interface is allowed
(and we will also throw one if the class is simply not found).
* If this happens, the bucket key for the class is reset, so
it's possibly to try registering the same class again.
* However, if the class has already been used due to a variance
obligation, the exception is upgraded to a fatal error, as we
cannot safely unregister the class stub anymore.
The requirements for parent/interface are difference than for the
variance checks in type declarations. The latter can work on fully
unlinked classes, but the former need inheritance to be essentially
finished, only variance checks may still be outstanding.
Adding a new flag for this because we have lots of space, but we
could also represent these "inheritance states" more compactly in
the future.
C99 no longer has implicit function declarations and implicit ints.
Current GCC versions enable them as an extension, but this will
change in a future GCC version.
ValueError is intended to be thrown when a function or method receives
an argument that has the right type (incorrect type should throw a
TypeError) but an inappropriate value.
I lost some time trying to know how to find the returned type.
It's not that obvious it is stored in the _argument_ information array.
For the sake of Internet, here is the full code checking that a function _has_ a returned type:
```c
zend_function *function = /* e.g. fci_cache->function_handler */;
if (!(function->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
php_printf("no return type\n");
} else {
php_printf("has a return type\n");
php_printf("return type = %s\n", zend_get_type_by_const(ZEND_TYPE_CODE(function->common.arg_info[-1].type)));
}
```
Instead of checking for this during DO_FCALL, already detect this
case during get_method()/get_static_method(), similar to visibility
checks.
This causes a minor difference in behavior, in that arguments will
no longer be evaluated. I think this is correct though (and consistent
with visibility errors).
We need to make sure that the function is fully compiled before we
calculate the stack size. There already was a check for directly
recursive calls, but the same issue exists with indirectly recursive
calls.
I'm using DONE_PASS_TWO as the indication that the function is
fully compiled.
* PHP-7.4:
Remove HOT attribute from some VM handlers. Comparisons almost always followed by JMPZ/JMPNZ; JMPZNZ is rare used.
Remove --with-zlib-dir option from mysqlnd config
The exception mechanism assumes that exceptions from DO_FCALL are
already happening after the function call. This means that we are
currently leaking the passed arguments, and I think we can also
corrupt the VM stack due to incorrect frame linking in some cases
(there are assertion failures if the VM stack page size is reduced).
Instead handle the stack frame freeing manually for this special
case.
The returned value must match the specified type exactly, as we
can't perform any coercions in non-debug builds.
Fix incorrect stub for easter_date() that slipped through the
assertion for this reason...
* PHP-7.4:
Free two bits in fn_flags by merging ZEND_ACC_HEAP_RT_CACHE/ZEND_ACC_USER_ARG_INFO and ZEND_ACC_DONE_PASS_TWO/ZEND_ACC_ARENA_ALLOCATED that may be used only for user/internal functions