Skip to content

Allow assignment to properties of objects stored in constants #11788

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

Closed
wants to merge 1 commit into from

Conversation

iluuu1994
Copy link
Member

@iluuu1994 iluuu1994 commented Jul 25, 2023

Fixes GH-11781

iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Jul 25, 2023
iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Jul 25, 2023
@iluuu1994 iluuu1994 marked this pull request as ready for review July 26, 2023 09:35
@iluuu1994 iluuu1994 requested a review from dstogov July 26, 2023 09:36
@iluuu1994
Copy link
Member Author

Hmm, FOO->array[] = 42; is still an issue. I'll see how easy it is to fix.

iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Jul 27, 2023
@iluuu1994
Copy link
Member Author

Ok, I found a much simpler solution that works for this case too.

@dstogov
Copy link
Member

dstogov commented Jul 31, 2023

Can you clarify? The lhs of -> is neither a reference nor an indirect value in this case, as it is the value of the constant, i.e. a IS_OBJ zval.

Looking into this patch it's not clear what instructions may be changed. I guess it is only FETCH_CONST and it is probably safe to change its result from TMP to VAR, but it's defenetly not safe for other instructions (as FETCH_DIM/OBJ_R).

If this patch intends to change only the FETCH_CONST instruction, it's better to do this in a more obvious way.

I can think of three options:

Change the result of FETCH_CONST to VAR only where necessary (what I do in this PR).

Adding ZEND_ASSERT(some_opline->opcode == ZEND_FETCH_CONSTANT) is going to be enough to make this clear.
What about FETCH_CLASS_CONSTANT?

Add TMP to OP1 in all the relevant handlers (ZEND_ASSIGN_OBJ, ZEND_FETCH_OBJ_W, etc). With TMPVAR this shouldn't actually change the size of the VM, or impact performance.
Change the result of all FETCH_CONST to VAR. This would have a negative performance impact due to added reference/indirect checks when using the result.

These approches look worse.

@iluuu1994
Copy link
Member Author

Ah, thank you for clarifying. You're right, adding an assert would certainly be more clear.

but it's defenetly not safe for other instructions (as FETCH_DIM/OBJ_R).

I'm still a bit confused about this. This is my understanding, please correct me if I'm wrong. VAR differs from TMP in that it adds IS_REF and IS_INDIRECT unwrapping when necessary. Thus, changing an operand from TMP to VAR would perform these checks, even if they are unnecessary. As long as the handler has a specialization for VAR, that should work fine. The opposite is of course not sound, as omitting the IS_REF and IS_INDIRECT unwrapping would lead to unexpected values. It seems to me FETCH_DIM_R with the lhs being a VAR should work fine, even if it is "only" a TMP (i.e. we know it can't contain references or indirect values.

Sorry if I'm missing the point.

@dstogov
Copy link
Member

dstogov commented Aug 1, 2023

Sorry if I'm missing the point.

If you change FETCH_DIM_R/TMP to FETCH_DIM_R/VAR, the following ASSING_DIM/OBJ won't change the element of the first array anyway. In addition the behaviour of FETCH_OBJ_R/TMP -> VAR may be affected by custom object handlers.

May be I'm wrong and changing TMP to VAR will work, but anyway I wouldn't recommend to do this without an extra care.

@valerio-bozzolan
Copy link

(Title typo: -cosntants +constants)

@iluuu1994 iluuu1994 changed the title Allow assignment to properties of objects stored in cosntants Allow assignment to properties of objects stored in constants Aug 10, 2023
iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Aug 10, 2023
if ((type == BP_VAR_W || type == BP_VAR_RW)) {
if (obj_node.op_type == IS_TMP_VAR) {
ZEND_ASSERT(obj_ast->kind == ZEND_AST_CONST);
obj_node.op_type = IS_VAR;
Copy link
Member

Choose a reason for hiding this comment

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

This means that FETCH_CONSTANT opline has result_type IS_TMP_VAR and the following instruction use it as IS_VAR.

<?php
class Foo {
    public $array = [];
}
const FOO = new Foo();
FOO->array[] = 42;
0000 DECLARE_CONST string("FOO") zval(type=11)
0001 T1 = FETCH_CONSTANT string("FOO")
0002 V0 = FETCH_OBJ_W (dim write) V1 string("array")
0003 ASSIGN_DIM V0 NEXT
0004 OP_DATA int(42)

This may confuse some code in optimizer where we check if result and usage types are the same.
Can you also change the result_type of FETCH_CONSANT?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch. I wonder if at that point it's better to just adjust the VM handlers to TMPVAR, rather than convoluting the compiler. I suppose alternatively we could use a QM_ASSIGN here too, unless the optimizer removes it again.

Copy link
Member

Choose a reason for hiding this comment

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

Do you see any problem in setting FETCH_CONSANT.result_type to IS_TMP_VAR?

I wonder if at that point it's better to just adjust the VM handlers to TMPVAR

This should introduce some overhead for all modified FETCH_..._W/RW or no?

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you see any problem in setting FETCH_CONSANT.result_type to IS_TMP_VAR?

I don't see a problem. It might just introduce slightly more complexity in the compiler.

This should introduce some overhead for all modified FETCH_..._W/RW or no?

I didn't think so, because we're changing them from VAR to TMPVAR. This should not actually change the specialized handlers. I will verify whether my assumption is correct. However, I will try your suggestion (changing result of FETCH_CONSTANT) first.

Copy link
Member

Choose a reason for hiding this comment

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

I mean changing FETCH_CONSTANT.result_type only for this case.

ZEND_ASSERT(opline->opcode == ZEND_FETCH_CONSTANT);
opline->result_type = IS_TMP_VAR;

May be my idea is wrong.

iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Sep 4, 2023
iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Sep 4, 2023
iluuu1994 added a commit to iluuu1994/php-src that referenced this pull request Sep 4, 2023
@iluuu1994
Copy link
Member Author

Doesn't seem worth the trouble.

@iluuu1994 iluuu1994 closed this Feb 8, 2024
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.

Error on writing const object property in 8.2
3 participants