Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix GH-17577: JIT packed type guard crash #17584

Open
wants to merge 1 commit into
base: PHP-8.3
Choose a base branch
from

Conversation

nielsdos
Copy link
Member

@nielsdos nielsdos commented Jan 26, 2025

When a guard check is created for a variable to check if it's a packed array, it is possible that there was no prior type check for that variable. This happens in the global scope for example when the variable aliases. In the test, this causes a dereference of address 8 because the integer element in $a is interpreted as an array address and zend_array.u.flags is at offset 8.

This patch adds a check to see if the guard is handled.

If we were not able to determine or guard the type is array, then we also cannot know the array is packed.
An alternative I thought about was emitting a type check in this branch, but that can cause incorrect guard motion in case of aliasing. In such case we also shouldn't clear the MAY_BE_PACKED_GUARD like it does now.

@nielsdos nielsdos linked an issue Jan 26, 2025 that may be closed by this pull request
@nielsdos nielsdos force-pushed the fix-17577 branch 3 times, most recently from ab89b9b to b477345 Compare January 26, 2025 13:57
@nielsdos nielsdos marked this pull request as ready for review January 26, 2025 15:22
@nielsdos nielsdos requested a review from dstogov as a code owner January 26, 2025 15:22
When a guard check is created for a variable to check if it's a packed array,
it is possible that there was no prior type check for that variable.
This happens in the global scope for example when the variable aliases.
In the test, this causes a dereference of address 8 because the integer
element in `$a` is interpreted as an array address.

This patch adds a check to see if the guard is handled.
If we were not able to determine or guard the type then we also cannot know the array is packed.
Copy link
Member

@dstogov dstogov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patch fixes the problem, but I think it might be better not to add MAY_BE_PACKED_GUARD in the first place. This may be done by checking op1_info & (MAY_BE_ANY|MAY_BE_UNDEF) == MY_BE_ARRAY.

What do you think? may be I miss something.

@nielsdos
Copy link
Member Author

The particular code responsible for setting MAY_BE_PACKED_GUARD is in the ZEND_FETCH_DIM_R case. Of course this is not the only place that would need modification, but just to show:

diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c
index c138a5bcb0a..8fd0d1323d0 100644
--- a/ext/opcache/jit/zend_jit_trace.c
+++ b/ext/opcache/jit/zend_jit_trace.c
@@ -1935,7 +1935,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
 
 						zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
 
-						if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
+						if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
+						 && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
 							info->type |= MAY_BE_PACKED_GUARD;
 							if (orig_op1_type & IS_TRACE_PACKED) {
 								info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
@@ -4162,7 +4163,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
 			}
 
 			if ((info & MAY_BE_PACKED_GUARD) != 0
-			 && (info & MAY_BE_GUARD) == 0
 			 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
 			  || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
 			  || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)

If I do this, and keep the assertion for the stack type to be IS_ARRAY, then the test added in this PR succeeds but bug80447.phpt gets an assertion failure.
This happens because #0.CV0($treeNode) has stack type IS_UNKNOWN because it has a MAY_BE_GUARD flag that cannot be motioned, so the stack type does not become IS_ARRAY. So I believe in this case we could still have an issue because we didn't ensure the variable is of type array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JIT packed type guard crash
2 participants